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