1b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Protocol Buffers - Google's data interchange format
2b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Copyright 2014 Google Inc.  All rights reserved.
3b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// https://developers.google.com/protocol-buffers/
4b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
5b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Redistribution and use in source and binary forms, with or without
6b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// modification, are permitted provided that the following conditions are
7b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// met:
8b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
9b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Redistributions of source code must retain the above copyright
10b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// notice, this list of conditions and the following disclaimer.
11b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Redistributions in binary form must reproduce the above
12b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// copyright notice, this list of conditions and the following disclaimer
13b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// in the documentation and/or other materials provided with the
14b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// distribution.
15b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Neither the name of Google Inc. nor the names of its
16b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// contributors may be used to endorse or promote products derived from
17b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// this software without specific prior written permission.
18b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
19b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
31b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include "protobuf.h"
32b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
33b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// This function is equivalent to rb_str_cat(), but unlike the real
34b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// rb_str_cat(), it doesn't leak memory in some versions of Ruby.
35b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// For more information, see:
36b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//   https://bugs.ruby-lang.org/issues/11328
37b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerVALUE noleak_rb_str_cat(VALUE rb_str, const char *str, long len) {
38b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  char *p;
39b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  size_t oldlen = RSTRING_LEN(rb_str);
40b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  rb_str_modify_expand(rb_str, len);
41b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  p = RSTRING_PTR(rb_str);
42b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  memcpy(p + oldlen, str, len);
43b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  rb_str_set_len(rb_str, oldlen + len);
44b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return rb_str;
45b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
46b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
47b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// -----------------------------------------------------------------------------
48b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Parsing.
49b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// -----------------------------------------------------------------------------
50b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
51b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#define DEREF(msg, ofs, type) *(type*)(((uint8_t *)msg) + ofs)
52b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
53b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Creates a handlerdata that simply contains the offset for this field.
54b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic const void* newhandlerdata(upb_handlers* h, uint32_t ofs) {
55b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  size_t* hd_ofs = ALLOC(size_t);
56b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  *hd_ofs = ofs;
57b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlers_addcleanup(h, hd_ofs, free);
58b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return hd_ofs;
59b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
60b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
61b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammertypedef struct {
62b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  size_t ofs;
63b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const upb_msgdef *md;
64b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer} submsg_handlerdata_t;
65b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
66b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Creates a handlerdata that contains offset and submessage type information.
67b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic const void *newsubmsghandlerdata(upb_handlers* h, uint32_t ofs,
68b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                        const upb_fielddef* f) {
69b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  submsg_handlerdata_t *hd = ALLOC(submsg_handlerdata_t);
70b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  hd->ofs = ofs;
71b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  hd->md = upb_fielddef_msgsubdef(f);
72b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlers_addcleanup(h, hd, free);
73b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return hd;
74b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
75b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
76b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammertypedef struct {
77b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  size_t ofs;              // union data slot
78b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  size_t case_ofs;         // oneof_case field
79b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint32_t oneof_case_num; // oneof-case number to place in oneof_case field
80b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const upb_msgdef *md;    // msgdef, for oneof submessage handler
81b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer} oneof_handlerdata_t;
82b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
83b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic const void *newoneofhandlerdata(upb_handlers *h,
84b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                       uint32_t ofs,
85b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                       uint32_t case_ofs,
86b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                       const upb_fielddef *f) {
87b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  oneof_handlerdata_t *hd = ALLOC(oneof_handlerdata_t);
88b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  hd->ofs = ofs;
89b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  hd->case_ofs = case_ofs;
90b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // We reuse the field tag number as a oneof union discriminant tag. Note that
91b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // we don't expose these numbers to the user, so the only requirement is that
92b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // we have some unique ID for each union case/possibility. The field tag
93b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // numbers are already present and are easy to use so there's no reason to
94b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // create a separate ID space. In addition, using the field tag number here
95b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // lets us easily look up the field in the oneof accessor.
96b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  hd->oneof_case_num = upb_fielddef_number(f);
97b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE) {
98b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    hd->md = upb_fielddef_msgsubdef(f);
99b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } else {
100b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    hd->md = NULL;
101b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
102b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlers_addcleanup(h, hd, free);
103b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return hd;
104b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
105b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
106b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// A handler that starts a repeated field.  Gets the Repeated*Field instance for
107b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// this field (such an instance always exists even in an empty message).
108b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void *startseq_handler(void* closure, const void* hd) {
109b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  MessageHeader* msg = closure;
110b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const size_t *ofs = hd;
111b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return (void*)DEREF(msg, *ofs, VALUE);
112b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
113b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
114b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Handlers that append primitive values to a repeated field.
115b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#define DEFINE_APPEND_HANDLER(type, ctype)                 \
116b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  static bool append##type##_handler(void *closure, const void *hd, \
117b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                     ctype val) {                   \
118b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    VALUE ary = (VALUE)closure;                                     \
119b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    RepeatedField_push_native(ary, &val);                           \
120b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return true;                                                    \
121b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
122b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
123b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerDEFINE_APPEND_HANDLER(bool,   bool)
124b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerDEFINE_APPEND_HANDLER(int32,  int32_t)
125b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerDEFINE_APPEND_HANDLER(uint32, uint32_t)
126b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerDEFINE_APPEND_HANDLER(float,  float)
127b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerDEFINE_APPEND_HANDLER(int64,  int64_t)
128b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerDEFINE_APPEND_HANDLER(uint64, uint64_t)
129b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerDEFINE_APPEND_HANDLER(double, double)
130b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
131b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Appends a string to a repeated field.
132b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void* appendstr_handler(void *closure,
133b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                               const void *hd,
134b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                               size_t size_hint) {
135b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE ary = (VALUE)closure;
136b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE str = rb_str_new2("");
137b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  rb_enc_associate(str, kRubyStringUtf8Encoding);
138b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  RepeatedField_push(ary, str);
139b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return (void*)str;
140b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
141b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
142b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Appends a 'bytes' string to a repeated field.
143b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void* appendbytes_handler(void *closure,
144b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                 const void *hd,
145b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                 size_t size_hint) {
146b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE ary = (VALUE)closure;
147b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE str = rb_str_new2("");
148b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  rb_enc_associate(str, kRubyString8bitEncoding);
149b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  RepeatedField_push(ary, str);
150b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return (void*)str;
151b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
152b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
153b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Sets a non-repeated string field in a message.
154b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void* str_handler(void *closure,
155b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                         const void *hd,
156b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                         size_t size_hint) {
157b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  MessageHeader* msg = closure;
158b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const size_t *ofs = hd;
159b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE str = rb_str_new2("");
160b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  rb_enc_associate(str, kRubyStringUtf8Encoding);
161b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  DEREF(msg, *ofs, VALUE) = str;
162b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return (void*)str;
163b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
164b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
165b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Sets a non-repeated 'bytes' field in a message.
166b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void* bytes_handler(void *closure,
167b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                           const void *hd,
168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                           size_t size_hint) {
169b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  MessageHeader* msg = closure;
170b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const size_t *ofs = hd;
171b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE str = rb_str_new2("");
172b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  rb_enc_associate(str, kRubyString8bitEncoding);
173b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  DEREF(msg, *ofs, VALUE) = str;
174b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return (void*)str;
175b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
176b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
177b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic size_t stringdata_handler(void* closure, const void* hd,
178b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                 const char* str, size_t len,
179b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                 const upb_bufhandle* handle) {
180b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE rb_str = (VALUE)closure;
181b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  noleak_rb_str_cat(rb_str, str, len);
182b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return len;
183b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
184b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
185b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Appends a submessage to a repeated field (a regular Ruby array for now).
186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void *appendsubmsg_handler(void *closure, const void *hd) {
187b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE ary = (VALUE)closure;
188b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const submsg_handlerdata_t *submsgdata = hd;
189b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE subdesc =
190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      get_def_obj((void*)submsgdata->md);
191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE subklass = Descriptor_msgclass(subdesc);
192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  MessageHeader* submsg;
193b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE submsg_rb = rb_class_new_instance(0, NULL, subklass);
195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  RepeatedField_push(ary, submsg_rb);
196b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
197b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
198b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return submsg;
199b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
200b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
201b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Sets a non-repeated submessage field in a message.
202b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void *submsg_handler(void *closure, const void *hd) {
203b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  MessageHeader* msg = closure;
204b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const submsg_handlerdata_t* submsgdata = hd;
205b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE subdesc =
206b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      get_def_obj((void*)submsgdata->md);
207b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE subklass = Descriptor_msgclass(subdesc);
208b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE submsg_rb;
209b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  MessageHeader* submsg;
210b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
211b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (DEREF(msg, submsgdata->ofs, VALUE) == Qnil) {
212b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    DEREF(msg, submsgdata->ofs, VALUE) =
213b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        rb_class_new_instance(0, NULL, subklass);
214b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
215b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
216b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  submsg_rb = DEREF(msg, submsgdata->ofs, VALUE);
217b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
218b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return submsg;
219b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
220b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
221b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Handler data for startmap/endmap handlers.
222b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammertypedef struct {
223b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  size_t ofs;
224b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_fieldtype_t key_field_type;
225b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_fieldtype_t value_field_type;
226b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
227b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // We know that we can hold this reference because the handlerdata has the
228b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // same lifetime as the upb_handlers struct, and the upb_handlers struct holds
229b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // a reference to the upb_msgdef, which in turn has references to its subdefs.
230b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const upb_def* value_field_subdef;
231b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer} map_handlerdata_t;
232b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
233b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Temporary frame for map parsing: at the beginning of a map entry message, a
234b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// submsg handler allocates a frame to hold (i) a reference to the Map object
235b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// into which this message will be inserted and (ii) storage slots to
236b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// temporarily hold the key and value for this map entry until the end of the
237b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// submessage. When the submessage ends, another handler is called to insert the
238b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// value into the map.
239b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammertypedef struct {
240b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE map;
241b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  char key_storage[NATIVE_SLOT_MAX_SIZE];
242b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  char value_storage[NATIVE_SLOT_MAX_SIZE];
243b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer} map_parse_frame_t;
244b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
245b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Handler to begin a map entry: allocates a temporary frame. This is the
246b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// 'startsubmsg' handler on the msgdef that contains the map field.
247b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void *startmapentry_handler(void *closure, const void *hd) {
248b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  MessageHeader* msg = closure;
249b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const map_handlerdata_t* mapdata = hd;
250b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE map_rb = DEREF(msg, mapdata->ofs, VALUE);
251b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
252b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  map_parse_frame_t* frame = ALLOC(map_parse_frame_t);
253b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  frame->map = map_rb;
254b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
255b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  native_slot_init(mapdata->key_field_type, &frame->key_storage);
256b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  native_slot_init(mapdata->value_field_type, &frame->value_storage);
257b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
258b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return frame;
259b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
260b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
261b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Handler to end a map entry: inserts the value defined during the message into
262b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// the map. This is the 'endmsg' handler on the map entry msgdef.
263b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic bool endmap_handler(void *closure, const void *hd, upb_status* s) {
264b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  map_parse_frame_t* frame = closure;
265b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const map_handlerdata_t* mapdata = hd;
266b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
267b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE key = native_slot_get(
268b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      mapdata->key_field_type, Qnil,
269b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &frame->key_storage);
270b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
271b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE value_field_typeclass = Qnil;
272b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE value;
273b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
274b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (mapdata->value_field_type == UPB_TYPE_MESSAGE ||
275b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      mapdata->value_field_type == UPB_TYPE_ENUM) {
276b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    value_field_typeclass = get_def_obj(mapdata->value_field_subdef);
277b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
278b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
279b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  value = native_slot_get(
280b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      mapdata->value_field_type, value_field_typeclass,
281b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &frame->value_storage);
282b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
283b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Map_index_set(frame->map, key, value);
284b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  free(frame);
285b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
286b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return true;
287b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
288b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
289b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Allocates a new map_handlerdata_t given the map entry message definition. If
290b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// the offset of the field within the parent message is also given, that is
291b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// added to the handler data as well. Note that this is called *twice* per map
292b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// field: once in the parent message handler setup when setting the startsubmsg
293b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// handler and once in the map entry message handler setup when setting the
294b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// key/value and endmsg handlers. The reason is that there is no easy way to
295b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// pass the handlerdata down to the sub-message handler setup.
296b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic map_handlerdata_t* new_map_handlerdata(
297b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    size_t ofs,
298b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    const upb_msgdef* mapentry_def,
299b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Descriptor* desc) {
300b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const upb_fielddef* key_field;
301b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const upb_fielddef* value_field;
302b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  map_handlerdata_t* hd = ALLOC(map_handlerdata_t);
303b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  hd->ofs = ofs;
304b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  key_field = upb_msgdef_itof(mapentry_def, MAP_KEY_FIELD);
305b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  assert(key_field != NULL);
306b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  hd->key_field_type = upb_fielddef_type(key_field);
307b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  value_field = upb_msgdef_itof(mapentry_def, MAP_VALUE_FIELD);
308b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  assert(value_field != NULL);
309b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  hd->value_field_type = upb_fielddef_type(value_field);
310b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  hd->value_field_subdef = upb_fielddef_subdef(value_field);
311b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
312b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return hd;
313b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
314b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
315b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Handlers that set primitive values in oneofs.
316b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#define DEFINE_ONEOF_HANDLER(type, ctype)                           \
317b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  static bool oneof##type##_handler(void *closure, const void *hd,  \
318b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                     ctype val) {                   \
319b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    const oneof_handlerdata_t *oneofdata = hd;                      \
320b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    DEREF(closure, oneofdata->case_ofs, uint32_t) =                 \
321b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        oneofdata->oneof_case_num;                                  \
322b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    DEREF(closure, oneofdata->ofs, ctype) = val;                    \
323b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return true;                                                    \
324b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
325b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
326b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerDEFINE_ONEOF_HANDLER(bool,   bool)
327b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerDEFINE_ONEOF_HANDLER(int32,  int32_t)
328b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerDEFINE_ONEOF_HANDLER(uint32, uint32_t)
329b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerDEFINE_ONEOF_HANDLER(float,  float)
330b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerDEFINE_ONEOF_HANDLER(int64,  int64_t)
331b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerDEFINE_ONEOF_HANDLER(uint64, uint64_t)
332b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerDEFINE_ONEOF_HANDLER(double, double)
333b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
334b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#undef DEFINE_ONEOF_HANDLER
335b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
336b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Handlers for strings in a oneof.
337b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void *oneofstr_handler(void *closure,
338b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                              const void *hd,
339b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                              size_t size_hint) {
340b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  MessageHeader* msg = closure;
341b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const oneof_handlerdata_t *oneofdata = hd;
342b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE str = rb_str_new2("");
343b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  rb_enc_associate(str, kRubyStringUtf8Encoding);
344b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  DEREF(msg, oneofdata->case_ofs, uint32_t) =
345b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      oneofdata->oneof_case_num;
346b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  DEREF(msg, oneofdata->ofs, VALUE) = str;
347b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return (void*)str;
348b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
349b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
350b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void *oneofbytes_handler(void *closure,
351b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                const void *hd,
352b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                size_t size_hint) {
353b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  MessageHeader* msg = closure;
354b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const oneof_handlerdata_t *oneofdata = hd;
355b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE str = rb_str_new2("");
356b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  rb_enc_associate(str, kRubyString8bitEncoding);
357b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  DEREF(msg, oneofdata->case_ofs, uint32_t) =
358b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      oneofdata->oneof_case_num;
359b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  DEREF(msg, oneofdata->ofs, VALUE) = str;
360b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return (void*)str;
361b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
362b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
363b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Handler for a submessage field in a oneof.
364b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void *oneofsubmsg_handler(void *closure,
365b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                 const void *hd) {
366b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  MessageHeader* msg = closure;
367b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const oneof_handlerdata_t *oneofdata = hd;
368b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint32_t oldcase = DEREF(msg, oneofdata->case_ofs, uint32_t);
369b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
370b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE subdesc =
371b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      get_def_obj((void*)oneofdata->md);
372b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE subklass = Descriptor_msgclass(subdesc);
373b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE submsg_rb;
374b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  MessageHeader* submsg;
375b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
376b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (oldcase != oneofdata->oneof_case_num ||
377b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      DEREF(msg, oneofdata->ofs, VALUE) == Qnil) {
378b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    DEREF(msg, oneofdata->ofs, VALUE) =
379b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        rb_class_new_instance(0, NULL, subklass);
380b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
381b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Set the oneof case *after* allocating the new class instance -- otherwise,
382b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // if the Ruby GC is invoked as part of a call into the VM, it might invoke
383b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // our mark routines, and our mark routines might see the case value
384b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // indicating a VALUE is present and expect a valid VALUE. See comment in
385b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // layout_set() for more detail: basically, the change to the value and the
386b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // case must be atomic w.r.t. the Ruby VM.
387b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  DEREF(msg, oneofdata->case_ofs, uint32_t) =
388b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      oneofdata->oneof_case_num;
389b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
390b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  submsg_rb = DEREF(msg, oneofdata->ofs, VALUE);
391b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  TypedData_Get_Struct(submsg_rb, MessageHeader, &Message_type, submsg);
392b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return submsg;
393b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
394b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
395b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Set up handlers for a repeated field.
396b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void add_handlers_for_repeated_field(upb_handlers *h,
397b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                            const upb_fielddef *f,
398b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                            size_t offset) {
399b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
400b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset));
401b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlers_setstartseq(h, f, startseq_handler, &attr);
402b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlerattr_uninit(&attr);
403b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
404b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  switch (upb_fielddef_type(f)) {
405b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
406b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#define SET_HANDLER(utype, ltype)                                 \
407b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  case utype:                                                     \
408b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_handlers_set##ltype(h, f, append##ltype##_handler, NULL); \
409b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    break;
410b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
411b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_BOOL,   bool);
412b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_INT32,  int32);
413b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_UINT32, uint32);
414b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_ENUM,   int32);
415b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_FLOAT,  float);
416b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_INT64,  int64);
417b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_UINT64, uint64);
418b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_DOUBLE, double);
419b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
420b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#undef SET_HANDLER
421b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
422b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_STRING:
423b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_BYTES: {
424b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
425b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlers_setstartstr(h, f, is_bytes ?
426b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                               appendbytes_handler : appendstr_handler,
427b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                               NULL);
428b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlers_setstring(h, f, stringdata_handler, NULL);
429b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
430b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
431b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_MESSAGE: {
432b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
433b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, 0, f));
434b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlers_setstartsubmsg(h, f, appendsubmsg_handler, &attr);
435b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlerattr_uninit(&attr);
436b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
437b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
438b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
439b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
440b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
441b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Set up handlers for a singular field.
442b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void add_handlers_for_singular_field(upb_handlers *h,
443b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                            const upb_fielddef *f,
444b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                            size_t offset) {
445b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  switch (upb_fielddef_type(f)) {
446b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_BOOL:
447b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_INT32:
448b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_UINT32:
449b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_ENUM:
450b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_FLOAT:
451b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_INT64:
452b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_UINT64:
453b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_DOUBLE:
454b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_shim_set(h, f, offset, -1);
455b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
456b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_STRING:
457b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_BYTES: {
458b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
459b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
460b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset));
461b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlers_setstartstr(h, f,
462b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                               is_bytes ? bytes_handler : str_handler,
463b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                               &attr);
464b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlers_setstring(h, f, stringdata_handler, &attr);
465b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlerattr_uninit(&attr);
466b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
467b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
468b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_MESSAGE: {
469b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
470b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, offset, f));
471b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr);
472b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlerattr_uninit(&attr);
473b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
474b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
475b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
476b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
477b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
478b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Adds handlers to a map field.
479b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void add_handlers_for_mapfield(upb_handlers* h,
480b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                      const upb_fielddef* fielddef,
481b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                      size_t offset,
482b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                      Descriptor* desc) {
483b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const upb_msgdef* map_msgdef = upb_fielddef_msgsubdef(fielddef);
484b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  map_handlerdata_t* hd = new_map_handlerdata(offset, map_msgdef, desc);
485b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
486b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
487b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlers_addcleanup(h, hd, free);
488b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlerattr_sethandlerdata(&attr, hd);
489b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlers_setstartsubmsg(h, fielddef, startmapentry_handler, &attr);
490b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlerattr_uninit(&attr);
491b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
492b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
493b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Adds handlers to a map-entry msgdef.
494b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void add_handlers_for_mapentry(const upb_msgdef* msgdef,
495b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                      upb_handlers* h,
496b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                      Descriptor* desc) {
497b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const upb_fielddef* key_field = map_entry_key(msgdef);
498b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const upb_fielddef* value_field = map_entry_value(msgdef);
499b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  map_handlerdata_t* hd = new_map_handlerdata(0, msgdef, desc);
500b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
501b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
502b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlers_addcleanup(h, hd, free);
503b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlerattr_sethandlerdata(&attr, hd);
504b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlers_setendmsg(h, endmap_handler, &attr);
505b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
506b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  add_handlers_for_singular_field(
507b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      h, key_field,
508b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      offsetof(map_parse_frame_t, key_storage));
509b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  add_handlers_for_singular_field(
510b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      h, value_field,
511b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      offsetof(map_parse_frame_t, value_storage));
512b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
513b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
514b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Set up handlers for a oneof field.
515b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void add_handlers_for_oneof_field(upb_handlers *h,
516b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                         const upb_fielddef *f,
517b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                         size_t offset,
518b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                         size_t oneof_case_offset) {
519b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
520b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
521b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlerattr_sethandlerdata(
522b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &attr, newoneofhandlerdata(h, offset, oneof_case_offset, f));
523b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
524b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  switch (upb_fielddef_type(f)) {
525b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
526b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#define SET_HANDLER(utype, ltype)                                 \
527b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  case utype:                                                     \
528b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_handlers_set##ltype(h, f, oneof##ltype##_handler, &attr); \
529b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    break;
530b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
531b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_BOOL,   bool);
532b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_INT32,  int32);
533b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_UINT32, uint32);
534b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_ENUM,   int32);
535b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_FLOAT,  float);
536b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_INT64,  int64);
537b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_UINT64, uint64);
538b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    SET_HANDLER(UPB_TYPE_DOUBLE, double);
539b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
540b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#undef SET_HANDLER
541b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
542b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_STRING:
543b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_BYTES: {
544b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
545b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlers_setstartstr(h, f, is_bytes ?
546b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                               oneofbytes_handler : oneofstr_handler,
547b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                               &attr);
548b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlers_setstring(h, f, stringdata_handler, NULL);
549b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
550b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
551b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_MESSAGE: {
552b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_handlers_setstartsubmsg(h, f, oneofsubmsg_handler, &attr);
553b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
554b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
555b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
556b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
557b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_handlerattr_uninit(&attr);
558b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
559b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
560b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
561b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void add_handlers_for_message(const void *closure, upb_handlers *h) {
562b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const upb_msgdef* msgdef = upb_handlers_msgdef(h);
563b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Descriptor* desc = ruby_to_Descriptor(get_def_obj((void*)msgdef));
564b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_msg_field_iter i;
565b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
566b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // If this is a mapentry message type, set up a special set of handlers and
567b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // bail out of the normal (user-defined) message type handling.
568b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (upb_msgdef_mapentry(msgdef)) {
569b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    add_handlers_for_mapentry(msgdef, h, desc);
570b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return;
571b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
572b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
573b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Ensure layout exists. We may be invoked to create handlers for a given
574b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // message if we are included as a submsg of another message type before our
575b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // class is actually built, so to work around this, we just create the layout
576b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // (and handlers, in the class-building function) on-demand.
577b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (desc->layout == NULL) {
578b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    desc->layout = create_layout(desc->msgdef);
579b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
580b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
581b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  for (upb_msg_field_begin(&i, desc->msgdef);
582b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer       !upb_msg_field_done(&i);
583b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer       upb_msg_field_next(&i)) {
584b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    const upb_fielddef *f = upb_msg_iter_field(&i);
585b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    size_t offset = desc->layout->fields[upb_fielddef_index(f)].offset +
586b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        sizeof(MessageHeader);
587b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
588b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (upb_fielddef_containingoneof(f)) {
589b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      size_t oneof_case_offset =
590b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          desc->layout->fields[upb_fielddef_index(f)].case_offset +
591b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          sizeof(MessageHeader);
592b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      add_handlers_for_oneof_field(h, f, offset, oneof_case_offset);
593b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else if (is_map_field(f)) {
594b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      add_handlers_for_mapfield(h, f, offset, desc);
595b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else if (upb_fielddef_isseq(f)) {
596b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      add_handlers_for_repeated_field(h, f, offset);
597b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else {
598b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      add_handlers_for_singular_field(h, f, offset);
599b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
600b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
601b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
602b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
603b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Creates upb handlers for populating a message.
604b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic const upb_handlers *new_fill_handlers(Descriptor* desc,
605b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                             const void* owner) {
606b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // TODO(cfallin, haberman): once upb gets a caching/memoization layer for
607b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // handlers, reuse subdef handlers so that e.g. if we already parse
608b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // B-with-field-of-type-C, we don't have to rebuild the whole hierarchy to
609b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // parse A-with-field-of-type-B-with-field-of-type-C.
610b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return upb_handlers_newfrozen(desc->msgdef, owner,
611b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                add_handlers_for_message, NULL);
612b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
613b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
614b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Constructs the handlers for filling a message's data into an in-memory
615b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// object.
616b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerconst upb_handlers* get_fill_handlers(Descriptor* desc) {
617b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (!desc->fill_handlers) {
618b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    desc->fill_handlers =
619b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        new_fill_handlers(desc, &desc->fill_handlers);
620b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
621b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return desc->fill_handlers;
622b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
623b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
624b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Constructs the upb decoder method for parsing messages of this type.
625b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// This is called from the message class creation code.
626b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerconst upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor* desc,
627b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                                     const void* owner) {
628b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const upb_handlers* handlers = get_fill_handlers(desc);
629b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_pbdecodermethodopts opts;
630b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_pbdecodermethodopts_init(&opts, handlers);
631b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
632b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return upb_pbdecodermethod_new(&opts, owner);
633b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
634b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
635b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) {
636b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (desc->fill_method == NULL) {
637b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    desc->fill_method = new_fillmsg_decodermethod(
638b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        desc, &desc->fill_method);
639b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
640b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return desc->fill_method;
641b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
642b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
643b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) {
644b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (desc->json_fill_method == NULL) {
645b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    desc->json_fill_method =
646b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        upb_json_parsermethod_new(desc->msgdef, &desc->json_fill_method);
647b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
648b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return desc->json_fill_method;
649b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
650b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
651b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
652b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Stack-allocated context during an encode/decode operation. Contains the upb
653b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// environment and its stack-based allocator, an initial buffer for allocations
654b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// to avoid malloc() when possible, and a template for Ruby exception messages
655b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// if any error occurs.
656b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#define STACK_ENV_STACKBYTES 4096
657b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammertypedef struct {
658b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_env env;
659b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const char* ruby_error_template;
660b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  char allocbuf[STACK_ENV_STACKBYTES];
661b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer} stackenv;
662b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
663b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void stackenv_init(stackenv* se, const char* errmsg);
664b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void stackenv_uninit(stackenv* se);
665b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
666b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Callback invoked by upb if any error occurs during parsing or serialization.
667b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic bool env_error_func(void* ud, const upb_status* status) {
668b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  stackenv* se = ud;
669b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Free the env -- rb_raise will longjmp up the stack past the encode/decode
670b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // function so it would not otherwise have been freed.
671b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  stackenv_uninit(se);
672b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
673b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // TODO(haberman): have a way to verify that this is actually a parse error,
674b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // instead of just throwing "parse error" unconditionally.
675b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  rb_raise(cParseError, se->ruby_error_template, upb_status_errmsg(status));
676b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Never reached: rb_raise() always longjmp()s up the stack, past all of our
677b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // code, back to Ruby.
678b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return false;
679b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
680b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
681b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void stackenv_init(stackenv* se, const char* errmsg) {
682b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  se->ruby_error_template = errmsg;
683b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_env_init2(&se->env, se->allocbuf, sizeof(se->allocbuf), NULL);
684b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_env_seterrorfunc(&se->env, env_error_func, se);
685b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
686b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
687b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void stackenv_uninit(stackenv* se) {
688b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_env_uninit(&se->env);
689b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
690b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
691b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/*
692b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * call-seq:
693b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *     MessageClass.decode(data) => message
694b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
695b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Decodes the given data (as a string containing bytes in protocol buffers wire
696b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * format) under the interpretration given by this message class's definition
697b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * and returns a message object with the corresponding field values.
698b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
699b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerVALUE Message_decode(VALUE klass, VALUE data) {
700b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
701b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Descriptor* desc = ruby_to_Descriptor(descriptor);
702b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE msgklass = Descriptor_msgclass(descriptor);
703b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE msg_rb;
704b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  MessageHeader* msg;
705b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
706b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (TYPE(data) != T_STRING) {
707b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    rb_raise(rb_eArgError, "Expected string for binary protobuf data.");
708b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
709b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
710b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  msg_rb = rb_class_new_instance(0, NULL, msgklass);
711b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
712b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
713b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  {
714b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    const upb_pbdecodermethod* method = msgdef_decodermethod(desc);
715b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    const upb_handlers* h = upb_pbdecodermethod_desthandlers(method);
716b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    stackenv se;
717b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_sink sink;
718b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_pbdecoder* decoder;
719b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    stackenv_init(&se, "Error occurred during parsing: %s");
720b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
721b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_sink_reset(&sink, h, msg);
722b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    decoder = upb_pbdecoder_create(&se.env, method, &sink);
723b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
724b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                      upb_pbdecoder_input(decoder));
725b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
726b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    stackenv_uninit(&se);
727b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
728b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
729b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return msg_rb;
730b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
731b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
732b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/*
733b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * call-seq:
734b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *     MessageClass.decode_json(data) => message
735b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
736b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Decodes the given data (as a string containing bytes in protocol buffers wire
737b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * format) under the interpretration given by this message class's definition
738b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * and returns a message object with the corresponding field values.
739b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
740b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerVALUE Message_decode_json(VALUE klass, VALUE data) {
741b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
742b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Descriptor* desc = ruby_to_Descriptor(descriptor);
743b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE msgklass = Descriptor_msgclass(descriptor);
744b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE msg_rb;
745b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  MessageHeader* msg;
746b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
747b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (TYPE(data) != T_STRING) {
748b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    rb_raise(rb_eArgError, "Expected string for JSON data.");
749b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
750b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to
751b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // convert, because string handlers pass data directly to message string
752b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // fields.
753b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
754b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  msg_rb = rb_class_new_instance(0, NULL, msgklass);
755b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
756b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
757b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  {
758b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    const upb_json_parsermethod* method = msgdef_jsonparsermethod(desc);
759b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    stackenv se;
760b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_sink sink;
761b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_json_parser* parser;
762b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    stackenv_init(&se, "Error occurred during parsing: %s");
763b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
764b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_sink_reset(&sink, get_fill_handlers(desc), msg);
765b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    parser = upb_json_parser_create(&se.env, method, &sink);
766b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data),
767b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                      upb_json_parser_input(parser));
768b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
769b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    stackenv_uninit(&se);
770b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
771b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
772b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return msg_rb;
773b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
774b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
775b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// -----------------------------------------------------------------------------
776b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Serializing.
777b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// -----------------------------------------------------------------------------
778b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
779b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// The code below also comes from upb's prototype Ruby binding, developed by
780b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// haberman@.
781b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
782b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/* stringsink *****************************************************************/
783b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
784b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// This should probably be factored into a common upb component.
785b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
786b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammertypedef struct {
787b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_byteshandler handler;
788b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_bytessink sink;
789b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  char *ptr;
790b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  size_t len, size;
791b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer} stringsink;
792b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
793b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void *stringsink_start(void *_sink, const void *hd, size_t size_hint) {
794b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  stringsink *sink = _sink;
795b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  sink->len = 0;
796b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return sink;
797b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
798b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
799b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic size_t stringsink_string(void *_sink, const void *hd, const char *ptr,
800b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                size_t len, const upb_bufhandle *handle) {
801b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  stringsink *sink = _sink;
802b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  size_t new_size = sink->size;
803b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
804b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  UPB_UNUSED(hd);
805b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  UPB_UNUSED(handle);
806b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
807b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  while (sink->len + len > new_size) {
808b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    new_size *= 2;
809b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
810b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
811b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (new_size != sink->size) {
812b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    sink->ptr = realloc(sink->ptr, new_size);
813b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    sink->size = new_size;
814b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
815b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
816b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  memcpy(sink->ptr + sink->len, ptr, len);
817b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  sink->len += len;
818b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
819b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return len;
820b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
821b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
822b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid stringsink_init(stringsink *sink) {
823b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_byteshandler_init(&sink->handler);
824b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_byteshandler_setstartstr(&sink->handler, stringsink_start, NULL);
825b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_byteshandler_setstring(&sink->handler, stringsink_string, NULL);
826b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
827b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_bytessink_reset(&sink->sink, &sink->handler, sink);
828b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
829b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  sink->size = 32;
830b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  sink->ptr = malloc(sink->size);
831b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  sink->len = 0;
832b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
833b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
834b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid stringsink_uninit(stringsink *sink) {
835b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  free(sink->ptr);
836b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
837b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
838b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/* msgvisitor *****************************************************************/
839b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
840b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// TODO: If/when we support proto2 semantics in addition to the current proto3
841b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// semantics, which means that we have true field presence, we will want to
842b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// modify msgvisitor so that it emits all present fields rather than all
843b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// non-default-value fields.
844b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
845b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Likewise, when implementing JSON serialization, we may need to have a
846b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// 'verbose' mode that outputs all fields and a 'concise' mode that outputs only
847b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// those with non-default values.
848b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
849b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void putmsg(VALUE msg, const Descriptor* desc,
850b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                   upb_sink *sink, int depth);
851b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
852b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
853b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_selector_t ret;
854b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  bool ok = upb_handlers_getselector(f, type, &ret);
855b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  UPB_ASSERT_VAR(ok, ok);
856b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return ret;
857b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
858b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
859b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void putstr(VALUE str, const upb_fielddef *f, upb_sink *sink) {
860b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink subsink;
861b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
862b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (str == Qnil) return;
863b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
864b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  assert(BUILTIN_TYPE(str) == RUBY_T_STRING);
865b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
866b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Ensure that the string has the correct encoding. We also check at field-set
867b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // time, but the user may have mutated the string object since then.
868b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  native_slot_validate_string_encoding(upb_fielddef_type(f), str);
869b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
870b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), RSTRING_LEN(str),
871b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    &subsink);
872b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink_putstring(&subsink, getsel(f, UPB_HANDLER_STRING), RSTRING_PTR(str),
873b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                     RSTRING_LEN(str), NULL);
874b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink_endstr(sink, getsel(f, UPB_HANDLER_ENDSTR));
875b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
876b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
877b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink,
878b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                      int depth) {
879b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink subsink;
880b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE descriptor;
881b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Descriptor* subdesc;
882b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
883b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (submsg == Qnil) return;
884b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
885b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  descriptor = rb_ivar_get(submsg, descriptor_instancevar_interned);
886b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  subdesc = ruby_to_Descriptor(descriptor);
887b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
888b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
889b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  putmsg(submsg, subdesc, &subsink, depth + 1);
890b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG));
891b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
892b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
893b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink,
894b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                   int depth) {
895b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink subsink;
896b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_fieldtype_t type = upb_fielddef_type(f);
897b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_selector_t sel = 0;
898b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  int size;
899b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
900b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (ary == Qnil) return;
901b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
902b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
903b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
904b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (upb_fielddef_isprimitive(f)) {
905b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
906b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
907b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
908b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  size = NUM2INT(RepeatedField_length(ary));
909b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  for (int i = 0; i < size; i++) {
910b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    void* memory = RepeatedField_index_native(ary, i);
911b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    switch (type) {
912b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#define T(upbtypeconst, upbtype, ctype)                         \
913b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  case upbtypeconst:                                            \
914b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_sink_put##upbtype(&subsink, sel, *((ctype *)memory));   \
915b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    break;
916b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
917b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      T(UPB_TYPE_FLOAT,  float,  float)
918b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      T(UPB_TYPE_DOUBLE, double, double)
919b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      T(UPB_TYPE_BOOL,   bool,   int8_t)
920b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case UPB_TYPE_ENUM:
921b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      T(UPB_TYPE_INT32,  int32,  int32_t)
922b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      T(UPB_TYPE_UINT32, uint32, uint32_t)
923b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      T(UPB_TYPE_INT64,  int64,  int64_t)
924b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      T(UPB_TYPE_UINT64, uint64, uint64_t)
925b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
926b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case UPB_TYPE_STRING:
927b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case UPB_TYPE_BYTES:
928b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        putstr(*((VALUE *)memory), f, &subsink);
929b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        break;
930b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case UPB_TYPE_MESSAGE:
931b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        putsubmsg(*((VALUE *)memory), f, &subsink, depth);
932b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        break;
933b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
934b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#undef T
935b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
936b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
937b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
938b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
939b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
940b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
941b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void put_ruby_value(VALUE value,
942b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                           const upb_fielddef *f,
943b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                           VALUE type_class,
944b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                           int depth,
945b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                           upb_sink *sink) {
946b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_selector_t sel = 0;
947b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (upb_fielddef_isprimitive(f)) {
948b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
949b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
950b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
951b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  switch (upb_fielddef_type(f)) {
952b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_INT32:
953b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_sink_putint32(sink, sel, NUM2INT(value));
954b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
955b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_INT64:
956b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_sink_putint64(sink, sel, NUM2LL(value));
957b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
958b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_UINT32:
959b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_sink_putuint32(sink, sel, NUM2UINT(value));
960b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
961b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_UINT64:
962b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_sink_putuint64(sink, sel, NUM2ULL(value));
963b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
964b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_FLOAT:
965b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_sink_putfloat(sink, sel, NUM2DBL(value));
966b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
967b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_DOUBLE:
968b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_sink_putdouble(sink, sel, NUM2DBL(value));
969b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
970b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_ENUM: {
971b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (TYPE(value) == T_SYMBOL) {
972b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        value = rb_funcall(type_class, rb_intern("resolve"), 1, value);
973b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
974b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_sink_putint32(sink, sel, NUM2INT(value));
975b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
976b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
977b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_BOOL:
978b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_sink_putbool(sink, sel, value == Qtrue);
979b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
980b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_STRING:
981b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_BYTES:
982b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      putstr(value, f, sink);
983b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
984b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case UPB_TYPE_MESSAGE:
985b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      putsubmsg(value, f, sink, depth);
986b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
987b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
988b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
989b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink,
990b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                   int depth) {
991b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Map* self;
992b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink subsink;
993b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const upb_fielddef* key_field;
994b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const upb_fielddef* value_field;
995b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Map_iter it;
996b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
997b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (map == Qnil) return;
998b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  self = ruby_to_Map(map);
999b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1000b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
1001b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1002b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  assert(upb_fielddef_type(f) == UPB_TYPE_MESSAGE);
1003b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  key_field = map_field_key(f);
1004b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  value_field = map_field_value(f);
1005b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1006b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  for (Map_begin(map, &it); !Map_done(&it); Map_next(&it)) {
1007b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    VALUE key = Map_iter_key(&it);
1008b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    VALUE value = Map_iter_value(&it);
1009b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_status status;
1010b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1011b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_sink entry_sink;
1012b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_sink_startsubmsg(&subsink, getsel(f, UPB_HANDLER_STARTSUBMSG),
1013b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                         &entry_sink);
1014b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_sink_startmsg(&entry_sink);
1015b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1016b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    put_ruby_value(key, key_field, Qnil, depth + 1, &entry_sink);
1017b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    put_ruby_value(value, value_field, self->value_type_class, depth + 1,
1018b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                   &entry_sink);
1019b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1020b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_sink_endmsg(&entry_sink, &status);
1021b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_sink_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
1022b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1023b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1024b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
1025b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1026b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1027b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic void putmsg(VALUE msg_rb, const Descriptor* desc,
1028b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                   upb_sink *sink, int depth) {
1029b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  MessageHeader* msg;
1030b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_msg_field_iter i;
1031b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_status status;
1032b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1033b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink_startmsg(sink);
1034b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1035b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Protect against cycles (possible because users may freely reassign message
1036b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // and repeated fields) by imposing a maximum recursion depth.
1037b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (depth > ENCODE_MAX_NESTING) {
1038b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    rb_raise(rb_eRuntimeError,
1039b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer             "Maximum recursion depth exceeded during encoding.");
1040b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1041b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1042b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg);
1043b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1044b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  for (upb_msg_field_begin(&i, desc->msgdef);
1045b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer       !upb_msg_field_done(&i);
1046b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer       upb_msg_field_next(&i)) {
1047b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_fielddef *f = upb_msg_iter_field(&i);
1048b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    bool is_matching_oneof = false;
1049b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    uint32_t offset =
1050b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        desc->layout->fields[upb_fielddef_index(f)].offset +
1051b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        sizeof(MessageHeader);
1052b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1053b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (upb_fielddef_containingoneof(f)) {
1054b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      uint32_t oneof_case_offset =
1055b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          desc->layout->fields[upb_fielddef_index(f)].case_offset +
1056b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          sizeof(MessageHeader);
1057b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // For a oneof, check that this field is actually present -- skip all the
1058b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // below if not.
1059b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (DEREF(msg, oneof_case_offset, uint32_t) !=
1060b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          upb_fielddef_number(f)) {
1061b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        continue;
1062b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1063b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Otherwise, fall through to the appropriate singular-field handler
1064b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // below.
1065b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      is_matching_oneof = true;
1066b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1067b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1068b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (is_map_field(f)) {
1069b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      VALUE map = DEREF(msg, offset, VALUE);
1070b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (map != Qnil) {
1071b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        putmap(map, f, sink, depth);
1072b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1073b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else if (upb_fielddef_isseq(f)) {
1074b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      VALUE ary = DEREF(msg, offset, VALUE);
1075b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (ary != Qnil) {
1076b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        putary(ary, f, sink, depth);
1077b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1078b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else if (upb_fielddef_isstring(f)) {
1079b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      VALUE str = DEREF(msg, offset, VALUE);
1080b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (is_matching_oneof || RSTRING_LEN(str) > 0) {
1081b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        putstr(str, f, sink);
1082b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1083b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else if (upb_fielddef_issubmsg(f)) {
1084b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      putsubmsg(DEREF(msg, offset, VALUE), f, sink, depth);
1085b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else {
1086b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
1087b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1088b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#define T(upbtypeconst, upbtype, ctype, default_value)                \
1089b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  case upbtypeconst: {                                                \
1090b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      ctype value = DEREF(msg, offset, ctype);                        \
1091b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (is_matching_oneof || value != default_value) {              \
1092b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        upb_sink_put##upbtype(sink, sel, value);                      \
1093b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }                                                               \
1094b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }                                                                 \
1095b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    break;
1096b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1097b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      switch (upb_fielddef_type(f)) {
1098b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        T(UPB_TYPE_FLOAT,  float,  float, 0.0)
1099b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        T(UPB_TYPE_DOUBLE, double, double, 0.0)
1100b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        T(UPB_TYPE_BOOL,   bool,   uint8_t, 0)
1101b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        case UPB_TYPE_ENUM:
1102b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        T(UPB_TYPE_INT32,  int32,  int32_t, 0)
1103b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        T(UPB_TYPE_UINT32, uint32, uint32_t, 0)
1104b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        T(UPB_TYPE_INT64,  int64,  int64_t, 0)
1105b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        T(UPB_TYPE_UINT64, uint64, uint64_t, 0)
1106b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1107b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        case UPB_TYPE_STRING:
1108b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        case UPB_TYPE_BYTES:
1109b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        case UPB_TYPE_MESSAGE: rb_raise(rb_eRuntimeError, "Internal error.");
1110b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1111b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1112b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#undef T
1113b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1114b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1115b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1116b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1117b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  upb_sink_endmsg(sink, &status);
1118b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1119b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1120b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) {
1121b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (desc->pb_serialize_handlers == NULL) {
1122b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    desc->pb_serialize_handlers =
1123b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        upb_pb_encoder_newhandlers(desc->msgdef, &desc->pb_serialize_handlers);
1124b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1125b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return desc->pb_serialize_handlers;
1126b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1127b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1128b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic const upb_handlers* msgdef_json_serialize_handlers(
1129b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Descriptor* desc, bool preserve_proto_fieldnames) {
1130b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (preserve_proto_fieldnames) {
1131b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (desc->json_serialize_handlers == NULL) {
1132b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      desc->json_serialize_handlers =
1133b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          upb_json_printer_newhandlers(
1134b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              desc->msgdef, true, &desc->json_serialize_handlers);
1135b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1136b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return desc->json_serialize_handlers;
1137b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } else {
1138b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (desc->json_serialize_handlers_preserve == NULL) {
1139b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      desc->json_serialize_handlers_preserve =
1140b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          upb_json_printer_newhandlers(
1141b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              desc->msgdef, false, &desc->json_serialize_handlers_preserve);
1142b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1143b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return desc->json_serialize_handlers_preserve;
1144b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1145b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1146b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1147b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/*
1148b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * call-seq:
1149b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *     MessageClass.encode(msg) => bytes
1150b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
1151b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Encodes the given message object to its serialized form in protocol buffers
1152b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * wire format.
1153b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
1154b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerVALUE Message_encode(VALUE klass, VALUE msg_rb) {
1155b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
1156b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Descriptor* desc = ruby_to_Descriptor(descriptor);
1157b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1158b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  stringsink sink;
1159b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  stringsink_init(&sink);
1160b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1161b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  {
1162b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    const upb_handlers* serialize_handlers =
1163b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        msgdef_pb_serialize_handlers(desc);
1164b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1165b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    stackenv se;
1166b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_pb_encoder* encoder;
1167b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    VALUE ret;
1168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1169b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    stackenv_init(&se, "Error occurred during encoding: %s");
1170b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink);
1171b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1172b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    putmsg(msg_rb, desc, upb_pb_encoder_input(encoder), 0);
1173b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1174b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ret = rb_str_new(sink.ptr, sink.len);
1175b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1176b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    stackenv_uninit(&se);
1177b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    stringsink_uninit(&sink);
1178b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1179b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return ret;
1180b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1181b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1182b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1183b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer/*
1184b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * call-seq:
1185b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *     MessageClass.encode_json(msg) => json_string
1186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer *
1187b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Encodes the given message object into its serialized JSON representation.
1188b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */
1189b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerVALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
1190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
1191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Descriptor* desc = ruby_to_Descriptor(descriptor);
1192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE msg_rb;
1193b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  VALUE preserve_proto_fieldnames = Qfalse;
1194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  stringsink sink;
1195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1196b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (argc < 1 || argc > 2) {
1197b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
1198b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1199b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1200b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  msg_rb = argv[0];
1201b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1202b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (argc == 2) {
1203b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    VALUE hash_args = argv[1];
1204b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (TYPE(hash_args) != T_HASH) {
1205b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      rb_raise(rb_eArgError, "Expected hash arguments.");
1206b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1207b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    preserve_proto_fieldnames = rb_hash_lookup2(
1208b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        hash_args, ID2SYM(rb_intern("preserve_proto_fieldnames")), Qfalse);
1209b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1210b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1211b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  stringsink_init(&sink);
1212b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1213b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  {
1214b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    const upb_handlers* serialize_handlers =
1215b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        msgdef_json_serialize_handlers(desc, RTEST(preserve_proto_fieldnames));
1216b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    upb_json_printer* printer;
1217b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    stackenv se;
1218b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    VALUE ret;
1219b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1220b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    stackenv_init(&se, "Error occurred during encoding: %s");
1221b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer = upb_json_printer_create(&se.env, serialize_handlers, &sink.sink);
1222b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1223b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    putmsg(msg_rb, desc, upb_json_printer_input(printer), 0);
1224b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1225b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ret = rb_enc_str_new(sink.ptr, sink.len, rb_utf8_encoding());
1226b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1227b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    stackenv_uninit(&se);
1228b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    stringsink_uninit(&sink);
1229b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1230b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return ret;
1231b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1232b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1233b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1234