sparsam 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/README.md +19 -0
 - data/ext/extconf.rb +18 -0
 - data/ext/ruby_hooks.c +96 -0
 - data/ext/serializer.cpp +716 -0
 - data/ext/serializer.h +101 -0
 - data/ext/third-party/sparsepp/sparsepp/spp.h +4347 -0
 - data/ext/third-party/sparsepp/sparsepp/spp_config.h +781 -0
 - data/ext/third-party/sparsepp/sparsepp/spp_dlalloc.h +4023 -0
 - data/ext/third-party/sparsepp/sparsepp/spp_memory.h +121 -0
 - data/ext/third-party/sparsepp/sparsepp/spp_smartptr.h +76 -0
 - data/ext/third-party/sparsepp/sparsepp/spp_stdint.h +16 -0
 - data/ext/third-party/sparsepp/sparsepp/spp_timer.h +58 -0
 - data/ext/third-party/sparsepp/sparsepp/spp_traits.h +122 -0
 - data/ext/third-party/sparsepp/sparsepp/spp_utils.h +447 -0
 - data/lib/sparsam.rb +10 -0
 - data/lib/sparsam/base_class.rb +97 -0
 - data/lib/sparsam/deserializer.rb +8 -0
 - data/lib/sparsam/exceptions.rb +33 -0
 - data/lib/sparsam/struct.rb +45 -0
 - data/lib/sparsam/types.rb +108 -0
 - data/lib/sparsam/union.rb +72 -0
 - data/spec/gen-ruby/user_constants.rb +9 -0
 - data/spec/gen-ruby/user_types.rb +106 -0
 - data/spec/sparsam_spec.rb +304 -0
 - data/spec/user.thrift +62 -0
 - metadata +172 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA1:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 3ab4bfb28dc0761f1ef66ea93e239408e4bdb308
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 78cd96b406e6260832478236d53e7c20a166d628
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 9c5cfdaed8ebc55ded0e937139d21d3133459be09b3787c6fc0625fdf09be2452d615969dbcd9aa7f7eb9510ec2bd1dd65c2314b9d979cabb043349f113cbc94
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 4a72dbf9b165aff8c419beaa7f870ed3cdb00e1d858201325707cdd5248d7e6ce6126896e9e4ae1e381c5e055003f4c8d348f95297e8143c270e86fe2bd198eb
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Sparsam [](https://travis-ci.org/airbnb/sparsam) [](https://coveralls.io/github/airbnb/sparsam?branch=master)
         
     | 
| 
      
 2 
     | 
    
         
            +
            New Thrift bindings and generator for Ruby!
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            ## Super basic Example
         
     | 
| 
      
 5 
     | 
    
         
            +
            See the docs folder for more detailed information
         
     | 
| 
      
 6 
     | 
    
         
            +
            ```
         
     | 
| 
      
 7 
     | 
    
         
            +
            $ sparsam-gen my_struct.thrift
         
     | 
| 
      
 8 
     | 
    
         
            +
            $ bundle exec irb
         
     | 
| 
      
 9 
     | 
    
         
            +
            irb(main):001:0> require './gen-ruby/my_struct_types'
         
     | 
| 
      
 10 
     | 
    
         
            +
            => true
         
     | 
| 
      
 11 
     | 
    
         
            +
            irb(main):002:0> require 'sparsam'
         
     | 
| 
      
 12 
     | 
    
         
            +
            => true
         
     | 
| 
      
 13 
     | 
    
         
            +
            irb(main):003:0> obj = MyStruct.new
         
     | 
| 
      
 14 
     | 
    
         
            +
            => #<MyStruct:0x007fa70d924148>
         
     | 
| 
      
 15 
     | 
    
         
            +
            irb(main):004:0> serialized = obj.serialize # turn object into string
         
     | 
| 
      
 16 
     | 
    
         
            +
            => "\x00"
         
     | 
| 
      
 17 
     | 
    
         
            +
            irb(main):005:0> obj2 = Sparsam::Deserializer.deserialize( MyStruct, serialized ) # deserialize string into obj
         
     | 
| 
      
 18 
     | 
    
         
            +
            => #<MyStruct:0x007fa70e3ee998>
         
     | 
| 
      
 19 
     | 
    
         
            +
            ```
         
     | 
    
        data/ext/extconf.rb
    ADDED
    
    | 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'mkmf'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            $CFLAGS = " -fsigned-char -O3 -ggdb3 -mtune=native "
         
     | 
| 
      
 5 
     | 
    
         
            +
            $CXXFLAGS = " -std=c++0x -O3 -ggdb3 -mtune=native -I./third-party/sparsepp "
         
     | 
| 
      
 6 
     | 
    
         
            +
            if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0')
         
     | 
| 
      
 7 
     | 
    
         
            +
              $CPPFLAGS += $CXXFLAGS
         
     | 
| 
      
 8 
     | 
    
         
            +
            end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            have_func("strlcpy", "string.h")
         
     | 
| 
      
 11 
     | 
    
         
            +
            have_library("thrift")
         
     | 
| 
      
 12 
     | 
    
         
            +
            libs = ['-lthrift']
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            libs.each do |lib|
         
     | 
| 
      
 15 
     | 
    
         
            +
              $LOCAL_LIBS << "#{lib} "
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            create_makefile 'sparsam_native'
         
     | 
    
        data/ext/ruby_hooks.c
    ADDED
    
    | 
         @@ -0,0 +1,96 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #include "serializer.h"
         
     | 
| 
      
 2 
     | 
    
         
            +
            #include "stdio.h"
         
     | 
| 
      
 3 
     | 
    
         
            +
            #include <ruby.h>
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            VALUE Sparsam = Qnil;
         
     | 
| 
      
 6 
     | 
    
         
            +
            VALUE static_zero_array;
         
     | 
| 
      
 7 
     | 
    
         
            +
            VALUE SparsamNativeError = Qnil;
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            ID intern_for_DEFAULT_VALUES;
         
     | 
| 
      
 10 
     | 
    
         
            +
            ID intern_for_assign_defaults;
         
     | 
| 
      
 11 
     | 
    
         
            +
            ID intern_for_assign_from_arg;
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            static void deallocate(void *data) { serializer_free(data); }
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            static VALUE allocate(VALUE klass) {
         
     | 
| 
      
 16 
     | 
    
         
            +
              void *data = serializer_create();
         
     | 
| 
      
 17 
     | 
    
         
            +
              return Data_Wrap_Struct(klass, NULL, deallocate, data);
         
     | 
| 
      
 18 
     | 
    
         
            +
            }
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            static VALUE sparsam_init_bang(VALUE self) {
         
     | 
| 
      
 21 
     | 
    
         
            +
              initialize_runtime_constants();
         
     | 
| 
      
 22 
     | 
    
         
            +
              return self;
         
     | 
| 
      
 23 
     | 
    
         
            +
            }
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            static VALUE initialize(VALUE self, VALUE type_arg, VALUE str_arg) {
         
     | 
| 
      
 26 
     | 
    
         
            +
              void *self_data = NULL;
         
     | 
| 
      
 27 
     | 
    
         
            +
              void *input_string = NULL;
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              Check_Type(type_arg, T_FIXNUM);
         
     | 
| 
      
 30 
     | 
    
         
            +
              int prot = NUM2INT(type_arg);
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              Check_Type(str_arg, T_STRING);
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              uint32_t len = RSTRING_LEN(str_arg);
         
     | 
| 
      
 35 
     | 
    
         
            +
              if (len != 0) {
         
     | 
| 
      
 36 
     | 
    
         
            +
                input_string = calloc(len, sizeof(char));
         
     | 
| 
      
 37 
     | 
    
         
            +
                memcpy(input_string, StringValuePtr(str_arg), len);
         
     | 
| 
      
 38 
     | 
    
         
            +
              }
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              Data_Get_Struct(self, void *, self_data);
         
     | 
| 
      
 41 
     | 
    
         
            +
              serializer_init(self_data, prot, input_string, len);
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
              return self;
         
     | 
| 
      
 44 
     | 
    
         
            +
            }
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            VALUE sparsam_struct_initialize(int argc, VALUE* argv, VALUE self) {
         
     | 
| 
      
 47 
     | 
    
         
            +
              if (argc > 1) {
         
     | 
| 
      
 48 
     | 
    
         
            +
                rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 0..1)", argc);
         
     | 
| 
      
 49 
     | 
    
         
            +
              }
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              VALUE defaults = rb_const_get(rb_obj_class(self), intern_for_DEFAULT_VALUES);
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
              if (defaults != Qnil) {
         
     | 
| 
      
 54 
     | 
    
         
            +
                rb_funcall(self, intern_for_assign_defaults, 1, defaults);
         
     | 
| 
      
 55 
     | 
    
         
            +
              }
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              if (argc == 1) {
         
     | 
| 
      
 58 
     | 
    
         
            +
                rb_funcall(self, intern_for_assign_from_arg, 1, argv[0]);
         
     | 
| 
      
 59 
     | 
    
         
            +
              }
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
              if (rb_block_given_p()) {
         
     | 
| 
      
 62 
     | 
    
         
            +
                rb_yield(self);
         
     | 
| 
      
 63 
     | 
    
         
            +
              }
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              return Qnil;
         
     | 
| 
      
 66 
     | 
    
         
            +
            }
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            void Init_sparsam_native() {
         
     | 
| 
      
 69 
     | 
    
         
            +
              Sparsam = rb_define_module("Sparsam");
         
     | 
| 
      
 70 
     | 
    
         
            +
              rb_define_singleton_method(Sparsam, "init!", sparsam_init_bang, 0);
         
     | 
| 
      
 71 
     | 
    
         
            +
              rb_define_singleton_method(Sparsam, "cache_fields", cache_fields, 1);
         
     | 
| 
      
 72 
     | 
    
         
            +
              rb_define_singleton_method(Sparsam, "validate", serializer_validate, 3);
         
     | 
| 
      
 73 
     | 
    
         
            +
              VALUE SparsamSerializer = rb_define_class_under(Sparsam, "Serializer", rb_cObject);
         
     | 
| 
      
 74 
     | 
    
         
            +
              SparsamNativeError =
         
     | 
| 
      
 75 
     | 
    
         
            +
                  rb_define_class_under(Sparsam, "Exception", rb_eStandardError);
         
     | 
| 
      
 76 
     | 
    
         
            +
              rb_define_alloc_func(SparsamSerializer, allocate);
         
     | 
| 
      
 77 
     | 
    
         
            +
              rb_define_method(SparsamSerializer, "initialize", initialize, 2);
         
     | 
| 
      
 78 
     | 
    
         
            +
              rb_define_method(SparsamSerializer, "serialize", serializer_writeStruct, 2);
         
     | 
| 
      
 79 
     | 
    
         
            +
              rb_define_method(SparsamSerializer, "deserialize", serializer_readStruct, 1);
         
     | 
| 
      
 80 
     | 
    
         
            +
              rb_define_const(Sparsam, "CompactProtocol", INT2FIX(compact));
         
     | 
| 
      
 81 
     | 
    
         
            +
              rb_define_const(Sparsam, "BinaryProtocol", INT2FIX(binary));
         
     | 
| 
      
 82 
     | 
    
         
            +
              rb_define_const(Sparsam, "UNION", INT2FIX(t_union));
         
     | 
| 
      
 83 
     | 
    
         
            +
              rb_define_const(Sparsam, "STRUCT", INT2FIX(t_struct));
         
     | 
| 
      
 84 
     | 
    
         
            +
              rb_define_const(Sparsam, "NORMAL", INT2FIX(normal));
         
     | 
| 
      
 85 
     | 
    
         
            +
              rb_define_const(Sparsam, "STRICT", INT2FIX(strict));
         
     | 
| 
      
 86 
     | 
    
         
            +
              rb_define_const(Sparsam, "RECURSIVE", INT2FIX(recursive));
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
              intern_for_DEFAULT_VALUES = rb_intern("DEFAULT_VALUES");
         
     | 
| 
      
 89 
     | 
    
         
            +
              intern_for_assign_defaults = rb_intern("assign_defaults");
         
     | 
| 
      
 90 
     | 
    
         
            +
              intern_for_assign_from_arg = rb_intern("assign_from_arg");
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
              VALUE SparsamStructInitialization = rb_define_module_under(Sparsam, "StructInitialization");
         
     | 
| 
      
 94 
     | 
    
         
            +
              rb_define_method(SparsamStructInitialization, "initialize", sparsam_struct_initialize, -1);
         
     | 
| 
      
 95 
     | 
    
         
            +
              initialize_constants();
         
     | 
| 
      
 96 
     | 
    
         
            +
            }
         
     | 
    
        data/ext/serializer.cpp
    ADDED
    
    | 
         @@ -0,0 +1,716 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #include "serializer.h"
         
     | 
| 
      
 2 
     | 
    
         
            +
            #include <functional>
         
     | 
| 
      
 3 
     | 
    
         
            +
            #include <map>
         
     | 
| 
      
 4 
     | 
    
         
            +
            #include <ruby/encoding.h>
         
     | 
| 
      
 5 
     | 
    
         
            +
            #include <stdio.h>
         
     | 
| 
      
 6 
     | 
    
         
            +
            #include <thrift/protocol/TBinaryProtocol.h>
         
     | 
| 
      
 7 
     | 
    
         
            +
            #include <thrift/protocol/TCompactProtocol.h>
         
     | 
| 
      
 8 
     | 
    
         
            +
            #include <boost/make_shared.hpp>
         
     | 
| 
      
 9 
     | 
    
         
            +
            #include <vector>
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            using namespace std;
         
     | 
| 
      
 12 
     | 
    
         
            +
            using ::apache::thrift::protocol::TType;
         
     | 
| 
      
 13 
     | 
    
         
            +
            using ::apache::thrift::transport::TMemoryBuffer;
         
     | 
| 
      
 14 
     | 
    
         
            +
            using namespace ::apache::thrift;
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            VALUE sym_for_class;
         
     | 
| 
      
 17 
     | 
    
         
            +
            VALUE sym_for_binary;
         
     | 
| 
      
 18 
     | 
    
         
            +
            VALUE sym_for_type;
         
     | 
| 
      
 19 
     | 
    
         
            +
            VALUE sym_for_element;
         
     | 
| 
      
 20 
     | 
    
         
            +
            VALUE sym_for_key;
         
     | 
| 
      
 21 
     | 
    
         
            +
            VALUE sym_for_value;
         
     | 
| 
      
 22 
     | 
    
         
            +
            VALUE sym_for_optional;
         
     | 
| 
      
 23 
     | 
    
         
            +
            VALUE sym_for_name;
         
     | 
| 
      
 24 
     | 
    
         
            +
            VALUE intern_for_FIELDS;
         
     | 
| 
      
 25 
     | 
    
         
            +
            VALUE intern_for_new;
         
     | 
| 
      
 26 
     | 
    
         
            +
            VALUE intern_for_keys;
         
     | 
| 
      
 27 
     | 
    
         
            +
            VALUE intern_for_values;
         
     | 
| 
      
 28 
     | 
    
         
            +
            ID intern_for_setfield_ivar;
         
     | 
| 
      
 29 
     | 
    
         
            +
            VALUE intern_for_to_a;
         
     | 
| 
      
 30 
     | 
    
         
            +
            VALUE klass_for_union;
         
     | 
| 
      
 31 
     | 
    
         
            +
            VALUE klass_for_integer;
         
     | 
| 
      
 32 
     | 
    
         
            +
            VALUE klass_for_float;
         
     | 
| 
      
 33 
     | 
    
         
            +
            VALUE klass_for_string;
         
     | 
| 
      
 34 
     | 
    
         
            +
            VALUE klass_for_hash;
         
     | 
| 
      
 35 
     | 
    
         
            +
            VALUE klass_for_set;
         
     | 
| 
      
 36 
     | 
    
         
            +
            VALUE klass_for_array;
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            extern VALUE Sparsam;
         
     | 
| 
      
 39 
     | 
    
         
            +
            extern VALUE SparsamNativeError;
         
     | 
| 
      
 40 
     | 
    
         
            +
            VALUE SparsamTypeMismatchError;
         
     | 
| 
      
 41 
     | 
    
         
            +
            VALUE SparsamMissingMandatory;
         
     | 
| 
      
 42 
     | 
    
         
            +
            VALUE SparsamUnionException;
         
     | 
| 
      
 43 
     | 
    
         
            +
            VALUE SparsamUnknownTypeException;
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
            KlassFieldsCache klassCache; // consider the memory leaked.
         
     | 
| 
      
 46 
     | 
    
         
            +
            std::unordered_set<VALUE> unions;
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            void *serializer_create() { return (void *)(new ThriftSerializer()); }
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            void serializer_free(void *data) {
         
     | 
| 
      
 51 
     | 
    
         
            +
              ThriftSerializer *ts = (ThriftSerializer *)(data);
         
     | 
| 
      
 52 
     | 
    
         
            +
              delete ts;
         
     | 
| 
      
 53 
     | 
    
         
            +
            }
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            void initialize_constants() {
         
     | 
| 
      
 56 
     | 
    
         
            +
              sym_for_class = ID2SYM(rb_intern("class"));
         
     | 
| 
      
 57 
     | 
    
         
            +
              sym_for_binary = ID2SYM(rb_intern("binary"));
         
     | 
| 
      
 58 
     | 
    
         
            +
              sym_for_type = ID2SYM(rb_intern("type"));
         
     | 
| 
      
 59 
     | 
    
         
            +
              sym_for_element = ID2SYM(rb_intern("element"));
         
     | 
| 
      
 60 
     | 
    
         
            +
              sym_for_key = ID2SYM(rb_intern("key"));
         
     | 
| 
      
 61 
     | 
    
         
            +
              sym_for_value = ID2SYM(rb_intern("value"));
         
     | 
| 
      
 62 
     | 
    
         
            +
              sym_for_optional = ID2SYM(rb_intern("optional"));
         
     | 
| 
      
 63 
     | 
    
         
            +
              sym_for_name = ID2SYM(rb_intern("name"));
         
     | 
| 
      
 64 
     | 
    
         
            +
              intern_for_FIELDS = rb_intern("FIELDS");
         
     | 
| 
      
 65 
     | 
    
         
            +
              intern_for_new = rb_intern("new");
         
     | 
| 
      
 66 
     | 
    
         
            +
              intern_for_keys = rb_intern("keys");
         
     | 
| 
      
 67 
     | 
    
         
            +
              intern_for_values = rb_intern("values");
         
     | 
| 
      
 68 
     | 
    
         
            +
              intern_for_to_a = rb_intern("to_a");
         
     | 
| 
      
 69 
     | 
    
         
            +
              intern_for_setfield_ivar = rb_intern("@setfield");
         
     | 
| 
      
 70 
     | 
    
         
            +
              klass_for_set = rb_const_get_at(rb_cObject, rb_intern("Set"));
         
     | 
| 
      
 71 
     | 
    
         
            +
              klass_for_integer = rb_const_get_at(rb_cObject, rb_intern("Integer"));
         
     | 
| 
      
 72 
     | 
    
         
            +
              klass_for_float = rb_const_get_at(rb_cObject, rb_intern("Float"));
         
     | 
| 
      
 73 
     | 
    
         
            +
              klass_for_string = rb_const_get_at(rb_cObject, rb_intern("String"));
         
     | 
| 
      
 74 
     | 
    
         
            +
              klass_for_hash = rb_const_get_at(rb_cObject, rb_intern("Hash"));
         
     | 
| 
      
 75 
     | 
    
         
            +
              klass_for_array = rb_const_get_at(rb_cObject, rb_intern("Array"));
         
     | 
| 
      
 76 
     | 
    
         
            +
            }
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
            void initialize_runtime_constants() {
         
     | 
| 
      
 79 
     | 
    
         
            +
              klass_for_union = rb_const_get_at(Sparsam, rb_intern("Union"));
         
     | 
| 
      
 80 
     | 
    
         
            +
              SparsamMissingMandatory = rb_const_get_at(Sparsam, rb_intern("MissingMandatory"));
         
     | 
| 
      
 81 
     | 
    
         
            +
              SparsamTypeMismatchError = rb_const_get_at(Sparsam, rb_intern("TypeMismatch"));
         
     | 
| 
      
 82 
     | 
    
         
            +
              SparsamUnionException = rb_const_get_at(Sparsam, rb_intern("UnionException"));
         
     | 
| 
      
 83 
     | 
    
         
            +
              SparsamUnknownTypeException =
         
     | 
| 
      
 84 
     | 
    
         
            +
                  rb_const_get_at(Sparsam, rb_intern("UnknownTypeException"));
         
     | 
| 
      
 85 
     | 
    
         
            +
            }
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            void serializer_init(void *serializer, int protocol, void *str_arg1,
         
     | 
| 
      
 88 
     | 
    
         
            +
                                 uint32_t len) {
         
     | 
| 
      
 89 
     | 
    
         
            +
              using ::boost::shared_ptr;
         
     | 
| 
      
 90 
     | 
    
         
            +
              using ::apache::thrift::protocol::TProtocol;
         
     | 
| 
      
 91 
     | 
    
         
            +
              using ::apache::thrift::protocol::TBinaryProtocol;
         
     | 
| 
      
 92 
     | 
    
         
            +
              using ::apache::thrift::protocol::TCompactProtocol;
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
              ThriftSerializer *ts = (ThriftSerializer *)(serializer);
         
     | 
| 
      
 95 
     | 
    
         
            +
              shared_ptr<TMemoryBuffer> strBuffer;
         
     | 
| 
      
 96 
     | 
    
         
            +
              if (str_arg1 != NULL) {
         
     | 
| 
      
 97 
     | 
    
         
            +
                strBuffer = boost::make_shared<TMemoryBuffer>(
         
     | 
| 
      
 98 
     | 
    
         
            +
                  (uint8_t *)str_arg1,
         
     | 
| 
      
 99 
     | 
    
         
            +
                  len,
         
     | 
| 
      
 100 
     | 
    
         
            +
                  TMemoryBuffer::TAKE_OWNERSHIP
         
     | 
| 
      
 101 
     | 
    
         
            +
                );
         
     | 
| 
      
 102 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 103 
     | 
    
         
            +
                strBuffer = boost::make_shared<TMemoryBuffer>();
         
     | 
| 
      
 104 
     | 
    
         
            +
              }
         
     | 
| 
      
 105 
     | 
    
         
            +
              Proto proto = static_cast<Proto>(protocol);
         
     | 
| 
      
 106 
     | 
    
         
            +
              if (proto == compact) {
         
     | 
| 
      
 107 
     | 
    
         
            +
                ts->tprot = shared_ptr<TProtocol>(new TCompactProtocol(strBuffer));
         
     | 
| 
      
 108 
     | 
    
         
            +
              } else if (proto == binary) {
         
     | 
| 
      
 109 
     | 
    
         
            +
                ts->tprot = shared_ptr<TProtocol>(new TBinaryProtocol(strBuffer));
         
     | 
| 
      
 110 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 111 
     | 
    
         
            +
                rb_raise(SparsamNativeError, "Unknown protocol %d", proto);
         
     | 
| 
      
 112 
     | 
    
         
            +
              }
         
     | 
| 
      
 113 
     | 
    
         
            +
              ts->tmb = strBuffer;
         
     | 
| 
      
 114 
     | 
    
         
            +
            }
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
            #define get_ts()                                                               \
         
     | 
| 
      
 117 
     | 
    
         
            +
              void *self_data = NULL;                                                      \
         
     | 
| 
      
 118 
     | 
    
         
            +
              Data_Get_Struct(self, void, self_data);                                      \
         
     | 
| 
      
 119 
     | 
    
         
            +
              ThriftSerializer *ts = (ThriftSerializer *)(self_data);
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
            #define watch_for_texcept() try {
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
            #define catch_thrift_and_reraise()                                             \
         
     | 
| 
      
 124 
     | 
    
         
            +
              }                                                                            \
         
     | 
| 
      
 125 
     | 
    
         
            +
              catch (::apache::thrift::TException e) {                                     \
         
     | 
| 
      
 126 
     | 
    
         
            +
                rb_raise(SparsamNativeError, "%s", e.what());                              \
         
     | 
| 
      
 127 
     | 
    
         
            +
                return Qnil;                                                               \
         
     | 
| 
      
 128 
     | 
    
         
            +
              }
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
            static inline VALUE make_ruby_string(const string &val) {
         
     | 
| 
      
 132 
     | 
    
         
            +
              return rb_enc_str_new(val.c_str(), val.size(), rb_utf8_encoding());
         
     | 
| 
      
 133 
     | 
    
         
            +
            }
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
            static inline VALUE make_ruby_binary(const string &val) {
         
     | 
| 
      
 136 
     | 
    
         
            +
              return rb_str_new(val.c_str(), val.size());
         
     | 
| 
      
 137 
     | 
    
         
            +
            }
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
            static inline VALUE make_ruby_bool(bool val) { return val ? Qtrue : Qfalse; }
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
            void ThriftSerializer::skip_n_type(uint32_t n, TType ttype) {
         
     | 
| 
      
 142 
     | 
    
         
            +
              for (uint32_t i = 0; i < n; i++) {
         
     | 
| 
      
 143 
     | 
    
         
            +
                this->tprot->skip(ttype);
         
     | 
| 
      
 144 
     | 
    
         
            +
              }
         
     | 
| 
      
 145 
     | 
    
         
            +
            }
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
            void ThriftSerializer::skip_n_pair(uint32_t n, TType type_a, TType type_b) {
         
     | 
| 
      
 148 
     | 
    
         
            +
              for (uint32_t i = 0; i < n; i++) {
         
     | 
| 
      
 149 
     | 
    
         
            +
                this->tprot->skip(type_a);
         
     | 
| 
      
 150 
     | 
    
         
            +
                this->tprot->skip(type_b);
         
     | 
| 
      
 151 
     | 
    
         
            +
              }
         
     | 
| 
      
 152 
     | 
    
         
            +
            }
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
            // Blatantly copied protobuf's design
         
     | 
| 
      
 155 
     | 
    
         
            +
            // https://git.io/vHuUn
         
     | 
| 
      
 156 
     | 
    
         
            +
            // CONVERT is new here, because we're targeting ruby
         
     | 
| 
      
 157 
     | 
    
         
            +
            #define HANDLE_TYPE(TYPE, CPPTYPE, READ_METHOD, CONVERT)                       \
         
     | 
| 
      
 158 
     | 
    
         
            +
              case protocol::T_##TYPE: {                                                   \
         
     | 
| 
      
 159 
     | 
    
         
            +
                CPPTYPE value;                                                             \
         
     | 
| 
      
 160 
     | 
    
         
            +
                this->tprot->read##READ_METHOD(value);                                     \
         
     | 
| 
      
 161 
     | 
    
         
            +
                ret = CONVERT(value);                                                      \
         
     | 
| 
      
 162 
     | 
    
         
            +
                break;                                                                     \
         
     | 
| 
      
 163 
     | 
    
         
            +
              }
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
            VALUE ThriftSerializer::readAny(TType ttype, FieldInfo *field_info) {
         
     | 
| 
      
 166 
     | 
    
         
            +
              VALUE ret = Qnil;
         
     | 
| 
      
 167 
     | 
    
         
            +
              switch (ttype) {
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
                // Handle all the non-container types by marco
         
     | 
| 
      
 170 
     | 
    
         
            +
                HANDLE_TYPE(I16, int16_t, I16, INT2FIX)
         
     | 
| 
      
 171 
     | 
    
         
            +
                HANDLE_TYPE(I32, int32_t, I32, INT2FIX)
         
     | 
| 
      
 172 
     | 
    
         
            +
                HANDLE_TYPE(I64, int64_t, I64, LL2NUM)
         
     | 
| 
      
 173 
     | 
    
         
            +
                HANDLE_TYPE(BOOL, bool, Bool, make_ruby_bool)
         
     | 
| 
      
 174 
     | 
    
         
            +
                HANDLE_TYPE(DOUBLE, double, Double, DBL2NUM)
         
     | 
| 
      
 175 
     | 
    
         
            +
                HANDLE_TYPE(BYTE, int8_t, Byte, INT2FIX)
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
              case protocol::T_STRING: {
         
     | 
| 
      
 178 
     | 
    
         
            +
                string value;
         
     | 
| 
      
 179 
     | 
    
         
            +
                if (field_info->isBinaryString) { // if (field_info[:binary])
         
     | 
| 
      
 180 
     | 
    
         
            +
                  this->tprot->readBinary(value);
         
     | 
| 
      
 181 
     | 
    
         
            +
                  ret = make_ruby_binary(value);
         
     | 
| 
      
 182 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 183 
     | 
    
         
            +
                  this->tprot->readString(value);
         
     | 
| 
      
 184 
     | 
    
         
            +
                  ret = make_ruby_string(value);
         
     | 
| 
      
 185 
     | 
    
         
            +
                }
         
     | 
| 
      
 186 
     | 
    
         
            +
                break;
         
     | 
| 
      
 187 
     | 
    
         
            +
              }
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
              case protocol::T_LIST: {
         
     | 
| 
      
 190 
     | 
    
         
            +
                TType element_type;
         
     | 
| 
      
 191 
     | 
    
         
            +
                uint32_t size;
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
                this->tprot->readListBegin(element_type, size);
         
     | 
| 
      
 194 
     | 
    
         
            +
                if (field_info->elementType == NULL ||
         
     | 
| 
      
 195 
     | 
    
         
            +
                    element_type != field_info->elementType->ftype) {
         
     | 
| 
      
 196 
     | 
    
         
            +
                  this->skip_n_type(size, element_type);
         
     | 
| 
      
 197 
     | 
    
         
            +
                  break;
         
     | 
| 
      
 198 
     | 
    
         
            +
                }
         
     | 
| 
      
 199 
     | 
    
         
            +
                ret = rb_ary_new2(size);
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
                for (uint32_t i = 0; i < size; i++) {
         
     | 
| 
      
 202 
     | 
    
         
            +
                  rb_ary_store(ret, i,
         
     | 
| 
      
 203 
     | 
    
         
            +
                               this->readAny(element_type, field_info->elementType));
         
     | 
| 
      
 204 
     | 
    
         
            +
                }
         
     | 
| 
      
 205 
     | 
    
         
            +
                this->tprot->readListEnd();
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
      
 207 
     | 
    
         
            +
                break;
         
     | 
| 
      
 208 
     | 
    
         
            +
              }
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
              case protocol::T_SET: {
         
     | 
| 
      
 211 
     | 
    
         
            +
                TType element_type;
         
     | 
| 
      
 212 
     | 
    
         
            +
                uint32_t size;
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
                this->tprot->readSetBegin(element_type, size);
         
     | 
| 
      
 215 
     | 
    
         
            +
                if (field_info->elementType == NULL ||
         
     | 
| 
      
 216 
     | 
    
         
            +
                    element_type != field_info->elementType->ftype) {
         
     | 
| 
      
 217 
     | 
    
         
            +
                  this->skip_n_type(size, element_type);
         
     | 
| 
      
 218 
     | 
    
         
            +
                  break;
         
     | 
| 
      
 219 
     | 
    
         
            +
                }
         
     | 
| 
      
 220 
     | 
    
         
            +
                VALUE ary = rb_ary_new2(size);
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
                for (uint32_t i = 0; i < size; i++) {
         
     | 
| 
      
 223 
     | 
    
         
            +
                  rb_ary_store(ary, i,
         
     | 
| 
      
 224 
     | 
    
         
            +
                               this->readAny(element_type, field_info->elementType));
         
     | 
| 
      
 225 
     | 
    
         
            +
                }
         
     | 
| 
      
 226 
     | 
    
         
            +
                ret = rb_class_new_instance(1, &ary, klass_for_set);
         
     | 
| 
      
 227 
     | 
    
         
            +
                this->tprot->readSetEnd();
         
     | 
| 
      
 228 
     | 
    
         
            +
                break;
         
     | 
| 
      
 229 
     | 
    
         
            +
              }
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
              case protocol::T_STRUCT: {
         
     | 
| 
      
 232 
     | 
    
         
            +
                string cname;
         
     | 
| 
      
 233 
     | 
    
         
            +
                this->tprot->readStructBegin(cname);
         
     | 
| 
      
 234 
     | 
    
         
            +
                if (unions.count(field_info->klass) == 1) {
         
     | 
| 
      
 235 
     | 
    
         
            +
                  ret = this->readUnion(field_info->klass);
         
     | 
| 
      
 236 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 237 
     | 
    
         
            +
                  ret = this->readStruct(field_info->klass);
         
     | 
| 
      
 238 
     | 
    
         
            +
                }
         
     | 
| 
      
 239 
     | 
    
         
            +
                this->tprot->readStructEnd();
         
     | 
| 
      
 240 
     | 
    
         
            +
                break;
         
     | 
| 
      
 241 
     | 
    
         
            +
              }
         
     | 
| 
      
 242 
     | 
    
         
            +
             
     | 
| 
      
 243 
     | 
    
         
            +
              case protocol::T_MAP: {
         
     | 
| 
      
 244 
     | 
    
         
            +
                TType key_type, value_type;
         
     | 
| 
      
 245 
     | 
    
         
            +
                uint32_t size;
         
     | 
| 
      
 246 
     | 
    
         
            +
                VALUE k, v;
         
     | 
| 
      
 247 
     | 
    
         
            +
             
     | 
| 
      
 248 
     | 
    
         
            +
                this->tprot->readMapBegin(key_type, value_type, size);
         
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
                if (field_info->keyType == NULL ||
         
     | 
| 
      
 251 
     | 
    
         
            +
                    field_info->elementType == NULL) { // no type check to be consistent
         
     | 
| 
      
 252 
     | 
    
         
            +
                  skip_n_pair(size, key_type, value_type);
         
     | 
| 
      
 253 
     | 
    
         
            +
                  break;
         
     | 
| 
      
 254 
     | 
    
         
            +
                }
         
     | 
| 
      
 255 
     | 
    
         
            +
             
     | 
| 
      
 256 
     | 
    
         
            +
                ret = rb_hash_new();
         
     | 
| 
      
 257 
     | 
    
         
            +
                for (uint32_t i = 0; i < size; i++) {
         
     | 
| 
      
 258 
     | 
    
         
            +
                  k = this->readAny(key_type, field_info->keyType);
         
     | 
| 
      
 259 
     | 
    
         
            +
                  v = this->readAny(value_type, field_info->elementType);
         
     | 
| 
      
 260 
     | 
    
         
            +
                  rb_hash_aset(ret, k, v);
         
     | 
| 
      
 261 
     | 
    
         
            +
                }
         
     | 
| 
      
 262 
     | 
    
         
            +
                this->tprot->readMapEnd();
         
     | 
| 
      
 263 
     | 
    
         
            +
                break;
         
     | 
| 
      
 264 
     | 
    
         
            +
              }
         
     | 
| 
      
 265 
     | 
    
         
            +
             
     | 
| 
      
 266 
     | 
    
         
            +
              default:
         
     | 
| 
      
 267 
     | 
    
         
            +
                this->tprot->skip(ttype);
         
     | 
| 
      
 268 
     | 
    
         
            +
                rb_raise(SparsamUnknownTypeException, "Received unknown type with id: %d", ttype);
         
     | 
| 
      
 269 
     | 
    
         
            +
                break;
         
     | 
| 
      
 270 
     | 
    
         
            +
              }
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
              return ret;
         
     | 
| 
      
 273 
     | 
    
         
            +
            }
         
     | 
| 
      
 274 
     | 
    
         
            +
             
     | 
| 
      
 275 
     | 
    
         
            +
            #undef HANDLE_TYPE
         
     | 
| 
      
 276 
     | 
    
         
            +
             
     | 
| 
      
 277 
     | 
    
         
            +
            VALUE ThriftSerializer::readStruct(VALUE klass) {
         
     | 
| 
      
 278 
     | 
    
         
            +
             
     | 
| 
      
 279 
     | 
    
         
            +
              string cname;
         
     | 
| 
      
 280 
     | 
    
         
            +
              FieldBegin fieldBegin;
         
     | 
| 
      
 281 
     | 
    
         
            +
              TType typeId;
         
     | 
| 
      
 282 
     | 
    
         
            +
              FieldInfo *fieldInfo;
         
     | 
| 
      
 283 
     | 
    
         
            +
              VALUE ret = rb_class_new_instance(0, NULL, klass); // ret = &klass.new
         
     | 
| 
      
 284 
     | 
    
         
            +
              auto fields = FindOrCreateFieldInfoMap(klass);
         
     | 
| 
      
 285 
     | 
    
         
            +
             
     | 
| 
      
 286 
     | 
    
         
            +
              while (true) {
         
     | 
| 
      
 287 
     | 
    
         
            +
                this->tprot->readFieldBegin(cname, fieldBegin.ftype, fieldBegin.fid);
         
     | 
| 
      
 288 
     | 
    
         
            +
                if (fieldBegin.ftype == protocol::T_STOP) {
         
     | 
| 
      
 289 
     | 
    
         
            +
                  break;
         
     | 
| 
      
 290 
     | 
    
         
            +
                }
         
     | 
| 
      
 291 
     | 
    
         
            +
                auto iter = fields->find(fieldBegin.fid);
         
     | 
| 
      
 292 
     | 
    
         
            +
             
     | 
| 
      
 293 
     | 
    
         
            +
                if (iter == fields->end()) {
         
     | 
| 
      
 294 
     | 
    
         
            +
                  this->tprot->skip(fieldBegin.ftype);
         
     | 
| 
      
 295 
     | 
    
         
            +
                  this->tprot->readFieldEnd();
         
     | 
| 
      
 296 
     | 
    
         
            +
                  continue;
         
     | 
| 
      
 297 
     | 
    
         
            +
                }
         
     | 
| 
      
 298 
     | 
    
         
            +
             
     | 
| 
      
 299 
     | 
    
         
            +
                fieldInfo = iter->second;
         
     | 
| 
      
 300 
     | 
    
         
            +
             
     | 
| 
      
 301 
     | 
    
         
            +
                typeId = fieldInfo->ftype;
         
     | 
| 
      
 302 
     | 
    
         
            +
             
     | 
| 
      
 303 
     | 
    
         
            +
                if (typeId != fieldBegin.ftype) {
         
     | 
| 
      
 304 
     | 
    
         
            +
                  rb_raise(SparsamTypeMismatchError, "Type Mismatch. Defenition: %d, Actual: %d",
         
     | 
| 
      
 305 
     | 
    
         
            +
                           fieldBegin.ftype, typeId);
         
     | 
| 
      
 306 
     | 
    
         
            +
                }
         
     | 
| 
      
 307 
     | 
    
         
            +
             
     | 
| 
      
 308 
     | 
    
         
            +
                VALUE rb_value = this->readAny(fieldBegin.ftype, iter->second);
         
     | 
| 
      
 309 
     | 
    
         
            +
                if (!NIL_P(rb_value)) {
         
     | 
| 
      
 310 
     | 
    
         
            +
                  rb_ivar_set(ret, fieldInfo->ivarName, rb_value);
         
     | 
| 
      
 311 
     | 
    
         
            +
                }
         
     | 
| 
      
 312 
     | 
    
         
            +
             
     | 
| 
      
 313 
     | 
    
         
            +
                this->tprot->readFieldEnd();
         
     | 
| 
      
 314 
     | 
    
         
            +
              }
         
     | 
| 
      
 315 
     | 
    
         
            +
              return ret;
         
     | 
| 
      
 316 
     | 
    
         
            +
            }
         
     | 
| 
      
 317 
     | 
    
         
            +
             
     | 
| 
      
 318 
     | 
    
         
            +
            VALUE ThriftSerializer::readUnion(VALUE klass) {
         
     | 
| 
      
 319 
     | 
    
         
            +
              string cname;
         
     | 
| 
      
 320 
     | 
    
         
            +
              FieldBegin fieldBegin;
         
     | 
| 
      
 321 
     | 
    
         
            +
             
     | 
| 
      
 322 
     | 
    
         
            +
              VALUE ret = rb_class_new_instance(0, NULL, klass); // ret = &klass.new
         
     | 
| 
      
 323 
     | 
    
         
            +
              auto fields = FindOrCreateFieldInfoMap(klass);
         
     | 
| 
      
 324 
     | 
    
         
            +
             
     | 
| 
      
 325 
     | 
    
         
            +
              VALUE key, rb_value;
         
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
      
 327 
     | 
    
         
            +
              this->tprot->readFieldBegin(cname, fieldBegin.ftype, fieldBegin.fid);
         
     | 
| 
      
 328 
     | 
    
         
            +
              if (fieldBegin.ftype == protocol::T_STOP) {
         
     | 
| 
      
 329 
     | 
    
         
            +
                return ret;
         
     | 
| 
      
 330 
     | 
    
         
            +
              }
         
     | 
| 
      
 331 
     | 
    
         
            +
             
     | 
| 
      
 332 
     | 
    
         
            +
              auto iter = fields->find(fieldBegin.fid);
         
     | 
| 
      
 333 
     | 
    
         
            +
             
     | 
| 
      
 334 
     | 
    
         
            +
              if (iter == fields->end()) {
         
     | 
| 
      
 335 
     | 
    
         
            +
                this->tprot->skip(fieldBegin.ftype);
         
     | 
| 
      
 336 
     | 
    
         
            +
                this->tprot->readFieldEnd();
         
     | 
| 
      
 337 
     | 
    
         
            +
                return ret;
         
     | 
| 
      
 338 
     | 
    
         
            +
              }
         
     | 
| 
      
 339 
     | 
    
         
            +
             
     | 
| 
      
 340 
     | 
    
         
            +
              rb_value = this->readAny(fieldBegin.ftype, iter->second);
         
     | 
| 
      
 341 
     | 
    
         
            +
              if (!NIL_P(rb_value)) {
         
     | 
| 
      
 342 
     | 
    
         
            +
                rb_ivar_set(ret, intern_for_setfield_ivar, iter->second->symName);
         
     | 
| 
      
 343 
     | 
    
         
            +
                rb_ivar_set(ret, iter->second->ivarName, rb_value);
         
     | 
| 
      
 344 
     | 
    
         
            +
              }
         
     | 
| 
      
 345 
     | 
    
         
            +
             
     | 
| 
      
 346 
     | 
    
         
            +
              this->tprot->readFieldEnd();
         
     | 
| 
      
 347 
     | 
    
         
            +
              this->tprot->readFieldBegin(cname, fieldBegin.ftype, fieldBegin.fid);
         
     | 
| 
      
 348 
     | 
    
         
            +
             
     | 
| 
      
 349 
     | 
    
         
            +
              if (fieldBegin.ftype != protocol::T_STOP) {
         
     | 
| 
      
 350 
     | 
    
         
            +
                rb_raise(SparsamUnionException, "More than one element in union.");
         
     | 
| 
      
 351 
     | 
    
         
            +
                return Qnil;
         
     | 
| 
      
 352 
     | 
    
         
            +
              }
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
              return ret;
         
     | 
| 
      
 355 
     | 
    
         
            +
            }
         
     | 
| 
      
 356 
     | 
    
         
            +
             
     | 
| 
      
 357 
     | 
    
         
            +
            // for the unary `+` before lambda:
         
     | 
| 
      
 358 
     | 
    
         
            +
            // https://stackoverflow.com/a/18889029/4944625
         
     | 
| 
      
 359 
     | 
    
         
            +
            // explicit cast to work with signature: (int (*)(...))
         
     | 
| 
      
 360 
     | 
    
         
            +
            #define HASH_FOREACH_BEGIN(hash, ...)                                          \
         
     | 
| 
      
 361 
     | 
    
         
            +
              void *_args[] = {__VA_ARGS__};                                               \
         
     | 
| 
      
 362 
     | 
    
         
            +
              rb_hash_foreach(hash, (int (*)(ANYARGS))(+[](VALUE k, VALUE v, VALUE args) { \
         
     | 
| 
      
 363 
     | 
    
         
            +
                void **argv = (void **) args;
         
     | 
| 
      
 364 
     | 
    
         
            +
             
     | 
| 
      
 365 
     | 
    
         
            +
            #define HASH_FOREACH_RET() return (int)ST_CONTINUE;
         
     | 
| 
      
 366 
     | 
    
         
            +
             
     | 
| 
      
 367 
     | 
    
         
            +
            #define HASH_FOREACH_ABORT() return (int)ST_STOP;
         
     | 
| 
      
 368 
     | 
    
         
            +
             
     | 
| 
      
 369 
     | 
    
         
            +
            #define HASH_FOREACH_END()                                                     \
         
     | 
| 
      
 370 
     | 
    
         
            +
              HASH_FOREACH_RET()                                                           \
         
     | 
| 
      
 371 
     | 
    
         
            +
              }), (VALUE) _args);
         
     | 
| 
      
 372 
     | 
    
         
            +
             
     | 
| 
      
 373 
     | 
    
         
            +
            #define HANDLE_TYPE(TYPE, WRITE_METHOD, CONVERT)                               \
         
     | 
| 
      
 374 
     | 
    
         
            +
              case protocol::T_##TYPE: {                                                   \
         
     | 
| 
      
 375 
     | 
    
         
            +
                this->tprot->write##WRITE_METHOD(CONVERT(actual));                         \
         
     | 
| 
      
 376 
     | 
    
         
            +
                break;                                                                     \
         
     | 
| 
      
 377 
     | 
    
         
            +
              }
         
     | 
| 
      
 378 
     | 
    
         
            +
             
     | 
| 
      
 379 
     | 
    
         
            +
            void ThriftSerializer::writeAny(TType ttype, FieldInfo *field_info,
         
     | 
| 
      
 380 
     | 
    
         
            +
                                            VALUE actual) {
         
     | 
| 
      
 381 
     | 
    
         
            +
              switch (ttype) {
         
     | 
| 
      
 382 
     | 
    
         
            +
                HANDLE_TYPE(I16, I16, NUM2SHORT)
         
     | 
| 
      
 383 
     | 
    
         
            +
                HANDLE_TYPE(I32, I32, NUM2INT)
         
     | 
| 
      
 384 
     | 
    
         
            +
                HANDLE_TYPE(I64, I64, NUM2LL)
         
     | 
| 
      
 385 
     | 
    
         
            +
                HANDLE_TYPE(BOOL, Bool, RTEST)
         
     | 
| 
      
 386 
     | 
    
         
            +
                HANDLE_TYPE(DOUBLE, Double, NUM2DBL)
         
     | 
| 
      
 387 
     | 
    
         
            +
                HANDLE_TYPE(BYTE, Byte, NUM2SHORT)
         
     | 
| 
      
 388 
     | 
    
         
            +
             
     | 
| 
      
 389 
     | 
    
         
            +
              case protocol::T_STRING: {
         
     | 
| 
      
 390 
     | 
    
         
            +
                string data = string(StringValuePtr(actual), RSTRING_LEN(actual));
         
     | 
| 
      
 391 
     | 
    
         
            +
                if (field_info->isBinaryString) {
         
     | 
| 
      
 392 
     | 
    
         
            +
                  this->tprot->writeBinary(data);
         
     | 
| 
      
 393 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 394 
     | 
    
         
            +
                  this->tprot->writeString(data);
         
     | 
| 
      
 395 
     | 
    
         
            +
                }
         
     | 
| 
      
 396 
     | 
    
         
            +
                break;
         
     | 
| 
      
 397 
     | 
    
         
            +
              }
         
     | 
| 
      
 398 
     | 
    
         
            +
             
     | 
| 
      
 399 
     | 
    
         
            +
              case protocol::T_LIST: {
         
     | 
| 
      
 400 
     | 
    
         
            +
                long length = RARRAY_LEN(actual);
         
     | 
| 
      
 401 
     | 
    
         
            +
                TType elem = field_info->elementType->ftype;
         
     | 
| 
      
 402 
     | 
    
         
            +
                this->tprot->writeListBegin(elem, static_cast<size_t>(length));
         
     | 
| 
      
 403 
     | 
    
         
            +
                for (long i = 0; i < length; i++) {
         
     | 
| 
      
 404 
     | 
    
         
            +
                  this->writeAny(elem, field_info->elementType, rb_ary_entry(actual, i));
         
     | 
| 
      
 405 
     | 
    
         
            +
                }
         
     | 
| 
      
 406 
     | 
    
         
            +
                this->tprot->writeListEnd();
         
     | 
| 
      
 407 
     | 
    
         
            +
                break;
         
     | 
| 
      
 408 
     | 
    
         
            +
              }
         
     | 
| 
      
 409 
     | 
    
         
            +
             
     | 
| 
      
 410 
     | 
    
         
            +
              case protocol::T_SET: {
         
     | 
| 
      
 411 
     | 
    
         
            +
                VALUE ary = rb_funcall(actual, intern_for_to_a, 0);
         
     | 
| 
      
 412 
     | 
    
         
            +
                long length = RARRAY_LEN(ary);
         
     | 
| 
      
 413 
     | 
    
         
            +
                TType elem = field_info->elementType->ftype;
         
     | 
| 
      
 414 
     | 
    
         
            +
                this->tprot->writeListBegin(elem, static_cast<size_t>(length));
         
     | 
| 
      
 415 
     | 
    
         
            +
                for (long i = 0; i < length; i++) {
         
     | 
| 
      
 416 
     | 
    
         
            +
                  this->writeAny(elem, field_info->elementType, rb_ary_entry(ary, i));
         
     | 
| 
      
 417 
     | 
    
         
            +
                }
         
     | 
| 
      
 418 
     | 
    
         
            +
                this->tprot->writeListEnd();
         
     | 
| 
      
 419 
     | 
    
         
            +
                break;
         
     | 
| 
      
 420 
     | 
    
         
            +
              }
         
     | 
| 
      
 421 
     | 
    
         
            +
             
     | 
| 
      
 422 
     | 
    
         
            +
              case protocol::T_MAP: {
         
     | 
| 
      
 423 
     | 
    
         
            +
                TType keyTType = field_info->keyType->ftype,
         
     | 
| 
      
 424 
     | 
    
         
            +
                      valueTType = field_info->elementType->ftype;
         
     | 
| 
      
 425 
     | 
    
         
            +
                this->tprot->writeMapBegin(keyTType, valueTType,
         
     | 
| 
      
 426 
     | 
    
         
            +
                                           static_cast<size_t>(RHASH_SIZE(actual)));
         
     | 
| 
      
 427 
     | 
    
         
            +
                HASH_FOREACH_BEGIN(actual, this, field_info)
         
     | 
| 
      
 428 
     | 
    
         
            +
                ThriftSerializer *that = (ThriftSerializer *)argv[0];
         
     | 
| 
      
 429 
     | 
    
         
            +
                FieldInfo *field_info = (FieldInfo *)argv[1];
         
     | 
| 
      
 430 
     | 
    
         
            +
                that->writeAny(field_info->keyType->ftype, field_info->keyType, k);
         
     | 
| 
      
 431 
     | 
    
         
            +
                that->writeAny(field_info->elementType->ftype, field_info->elementType, v);
         
     | 
| 
      
 432 
     | 
    
         
            +
                HASH_FOREACH_END()
         
     | 
| 
      
 433 
     | 
    
         
            +
                this->tprot->writeMapEnd();
         
     | 
| 
      
 434 
     | 
    
         
            +
                break;
         
     | 
| 
      
 435 
     | 
    
         
            +
              }
         
     | 
| 
      
 436 
     | 
    
         
            +
             
     | 
| 
      
 437 
     | 
    
         
            +
              case protocol::T_STRUCT: {
         
     | 
| 
      
 438 
     | 
    
         
            +
                static const string cname = "";
         
     | 
| 
      
 439 
     | 
    
         
            +
                this->tprot->writeStructBegin(cname.c_str());
         
     | 
| 
      
 440 
     | 
    
         
            +
                this->writeStruct(field_info->klass, actual);
         
     | 
| 
      
 441 
     | 
    
         
            +
                this->tprot->writeFieldStop();
         
     | 
| 
      
 442 
     | 
    
         
            +
                this->tprot->writeStructEnd();
         
     | 
| 
      
 443 
     | 
    
         
            +
                break;
         
     | 
| 
      
 444 
     | 
    
         
            +
              }
         
     | 
| 
      
 445 
     | 
    
         
            +
             
     | 
| 
      
 446 
     | 
    
         
            +
              default: { break; }
         
     | 
| 
      
 447 
     | 
    
         
            +
              }
         
     | 
| 
      
 448 
     | 
    
         
            +
            }
         
     | 
| 
      
 449 
     | 
    
         
            +
             
     | 
| 
      
 450 
     | 
    
         
            +
            #undef HANDLE_TYPE
         
     | 
| 
      
 451 
     | 
    
         
            +
             
     | 
| 
      
 452 
     | 
    
         
            +
            void ThriftSerializer::writeStruct(VALUE klass, VALUE data) {
         
     | 
| 
      
 453 
     | 
    
         
            +
              static const string cname = "";
         
     | 
| 
      
 454 
     | 
    
         
            +
              FieldBegin fieldBegin;
         
     | 
| 
      
 455 
     | 
    
         
            +
              FieldInfo *fieldInfo;
         
     | 
| 
      
 456 
     | 
    
         
            +
              auto fields = FindOrCreateFieldInfoMap(klass);
         
     | 
| 
      
 457 
     | 
    
         
            +
              for (auto const & entry : *fields) {
         
     | 
| 
      
 458 
     | 
    
         
            +
                fieldBegin.fid = entry.first;
         
     | 
| 
      
 459 
     | 
    
         
            +
                fieldInfo = entry.second;
         
     | 
| 
      
 460 
     | 
    
         
            +
                fieldBegin.ftype = fieldInfo->ftype;
         
     | 
| 
      
 461 
     | 
    
         
            +
                VALUE actual = rb_ivar_get(data, fieldInfo->ivarName);
         
     | 
| 
      
 462 
     | 
    
         
            +
                if (!NIL_P(actual)) {
         
     | 
| 
      
 463 
     | 
    
         
            +
                  this->tprot->writeFieldBegin(cname.c_str(), fieldBegin.ftype, fieldBegin.fid);
         
     | 
| 
      
 464 
     | 
    
         
            +
                  this->writeAny(fieldBegin.ftype, entry.second, actual);
         
     | 
| 
      
 465 
     | 
    
         
            +
                  this->tprot->writeFieldEnd();
         
     | 
| 
      
 466 
     | 
    
         
            +
                }
         
     | 
| 
      
 467 
     | 
    
         
            +
              }
         
     | 
| 
      
 468 
     | 
    
         
            +
            }
         
     | 
| 
      
 469 
     | 
    
         
            +
             
     | 
| 
      
 470 
     | 
    
         
            +
            VALUE serializer_writeStruct(VALUE self, VALUE klass, VALUE data) {
         
     | 
| 
      
 471 
     | 
    
         
            +
              watch_for_texcept() get_ts();
         
     | 
| 
      
 472 
     | 
    
         
            +
              static const string cname = "";
         
     | 
| 
      
 473 
     | 
    
         
            +
              ts->tprot->writeStructBegin(cname.c_str());
         
     | 
| 
      
 474 
     | 
    
         
            +
              ts->writeStruct(klass, data);
         
     | 
| 
      
 475 
     | 
    
         
            +
              ts->tprot->writeFieldStop();
         
     | 
| 
      
 476 
     | 
    
         
            +
              ts->tprot->writeStructEnd();
         
     | 
| 
      
 477 
     | 
    
         
            +
              string retval = ts->tmb->getBufferAsString();
         
     | 
| 
      
 478 
     | 
    
         
            +
              return rb_str_new(retval.c_str(), retval.size());
         
     | 
| 
      
 479 
     | 
    
         
            +
              catch_thrift_and_reraise();
         
     | 
| 
      
 480 
     | 
    
         
            +
            }
         
     | 
| 
      
 481 
     | 
    
         
            +
             
     | 
| 
      
 482 
     | 
    
         
            +
            VALUE serializer_readStruct(VALUE self, VALUE klass) {
         
     | 
| 
      
 483 
     | 
    
         
            +
              watch_for_texcept() get_ts();
         
     | 
| 
      
 484 
     | 
    
         
            +
              string cname;
         
     | 
| 
      
 485 
     | 
    
         
            +
              VALUE ret;
         
     | 
| 
      
 486 
     | 
    
         
            +
              ts->tprot->readStructBegin(cname);
         
     | 
| 
      
 487 
     | 
    
         
            +
              ret = ts->readStruct(klass);
         
     | 
| 
      
 488 
     | 
    
         
            +
              ts->tprot->readStructEnd();
         
     | 
| 
      
 489 
     | 
    
         
            +
              return ret;
         
     | 
| 
      
 490 
     | 
    
         
            +
              catch_thrift_and_reraise();
         
     | 
| 
      
 491 
     | 
    
         
            +
            }
         
     | 
| 
      
 492 
     | 
    
         
            +
             
     | 
| 
      
 493 
     | 
    
         
            +
            static inline void raise_type_mismatch() {
         
     | 
| 
      
 494 
     | 
    
         
            +
              rb_raise(SparsamTypeMismatchError, "Type mismatch in field data");
         
     | 
| 
      
 495 
     | 
    
         
            +
            }
         
     | 
| 
      
 496 
     | 
    
         
            +
             
     | 
| 
      
 497 
     | 
    
         
            +
            bool validateArray(FieldInfo *type, VALUE arr, bool recursive) {
         
     | 
| 
      
 498 
     | 
    
         
            +
              long length = RARRAY_LEN(arr);
         
     | 
| 
      
 499 
     | 
    
         
            +
              for (long i = 0; i < length; i++) {
         
     | 
| 
      
 500 
     | 
    
         
            +
                if (!validateAny(type, rb_ary_entry(arr, i), recursive)) {
         
     | 
| 
      
 501 
     | 
    
         
            +
                  rb_raise(SparsamTypeMismatchError, "Type mismatch in container element");
         
     | 
| 
      
 502 
     | 
    
         
            +
                  return false;
         
     | 
| 
      
 503 
     | 
    
         
            +
                }
         
     | 
| 
      
 504 
     | 
    
         
            +
              }
         
     | 
| 
      
 505 
     | 
    
         
            +
              return true;
         
     | 
| 
      
 506 
     | 
    
         
            +
            }
         
     | 
| 
      
 507 
     | 
    
         
            +
             
     | 
| 
      
 508 
     | 
    
         
            +
            #define TEST_RB_VAL_FOR_CLASS(VAL, KLASS)                                      \
         
     | 
| 
      
 509 
     | 
    
         
            +
              if (!RTEST(rb_obj_is_kind_of(VAL, KLASS))) {                                 \
         
     | 
| 
      
 510 
     | 
    
         
            +
                raise_type_mismatch();                                                     \
         
     | 
| 
      
 511 
     | 
    
         
            +
                ret = false;                                                               \
         
     | 
| 
      
 512 
     | 
    
         
            +
              }
         
     | 
| 
      
 513 
     | 
    
         
            +
             
     | 
| 
      
 514 
     | 
    
         
            +
            #define HANDLE_TYPE(TYPE, KLASS)                                               \
         
     | 
| 
      
 515 
     | 
    
         
            +
              case protocol::T_##TYPE: {                                                   \
         
     | 
| 
      
 516 
     | 
    
         
            +
                TEST_RB_VAL_FOR_CLASS(val, KLASS)                                          \
         
     | 
| 
      
 517 
     | 
    
         
            +
                break;                                                                     \
         
     | 
| 
      
 518 
     | 
    
         
            +
              }
         
     | 
| 
      
 519 
     | 
    
         
            +
             
     | 
| 
      
 520 
     | 
    
         
            +
            bool validateAny(FieldInfo *type, VALUE val, bool recursive) {
         
     | 
| 
      
 521 
     | 
    
         
            +
              bool ret = true;
         
     | 
| 
      
 522 
     | 
    
         
            +
              switch (type->ftype) {
         
     | 
| 
      
 523 
     | 
    
         
            +
             
     | 
| 
      
 524 
     | 
    
         
            +
                HANDLE_TYPE(BYTE, klass_for_integer)
         
     | 
| 
      
 525 
     | 
    
         
            +
                HANDLE_TYPE(I16, klass_for_integer)
         
     | 
| 
      
 526 
     | 
    
         
            +
                HANDLE_TYPE(I32, klass_for_integer)
         
     | 
| 
      
 527 
     | 
    
         
            +
                HANDLE_TYPE(I64, klass_for_integer)
         
     | 
| 
      
 528 
     | 
    
         
            +
                HANDLE_TYPE(DOUBLE, klass_for_float)
         
     | 
| 
      
 529 
     | 
    
         
            +
                HANDLE_TYPE(STRING, klass_for_string)
         
     | 
| 
      
 530 
     | 
    
         
            +
             
     | 
| 
      
 531 
     | 
    
         
            +
              case protocol::T_STRUCT: {
         
     | 
| 
      
 532 
     | 
    
         
            +
                TEST_RB_VAL_FOR_CLASS(val, type->klass)
         
     | 
| 
      
 533 
     | 
    
         
            +
                if (ret && recursive) {
         
     | 
| 
      
 534 
     | 
    
         
            +
                  ret = validateStruct(type->klass, val, true, recursive);
         
     | 
| 
      
 535 
     | 
    
         
            +
                }
         
     | 
| 
      
 536 
     | 
    
         
            +
                break;
         
     | 
| 
      
 537 
     | 
    
         
            +
              }
         
     | 
| 
      
 538 
     | 
    
         
            +
             
     | 
| 
      
 539 
     | 
    
         
            +
              case protocol::T_SET: {
         
     | 
| 
      
 540 
     | 
    
         
            +
                TEST_RB_VAL_FOR_CLASS(val, klass_for_set)
         
     | 
| 
      
 541 
     | 
    
         
            +
                if (ret) {
         
     | 
| 
      
 542 
     | 
    
         
            +
                  VALUE ary = rb_funcall(val, intern_for_to_a, 0);
         
     | 
| 
      
 543 
     | 
    
         
            +
                  ret = validateArray(type->elementType, ary, recursive);
         
     | 
| 
      
 544 
     | 
    
         
            +
                }
         
     | 
| 
      
 545 
     | 
    
         
            +
                break;
         
     | 
| 
      
 546 
     | 
    
         
            +
              }
         
     | 
| 
      
 547 
     | 
    
         
            +
              case protocol::T_LIST: {
         
     | 
| 
      
 548 
     | 
    
         
            +
                TEST_RB_VAL_FOR_CLASS(val, klass_for_array)
         
     | 
| 
      
 549 
     | 
    
         
            +
                if (ret) {
         
     | 
| 
      
 550 
     | 
    
         
            +
                  ret = validateArray(type->elementType, val, recursive);
         
     | 
| 
      
 551 
     | 
    
         
            +
                }
         
     | 
| 
      
 552 
     | 
    
         
            +
                break;
         
     | 
| 
      
 553 
     | 
    
         
            +
              }
         
     | 
| 
      
 554 
     | 
    
         
            +
             
     | 
| 
      
 555 
     | 
    
         
            +
              case protocol::T_MAP: {
         
     | 
| 
      
 556 
     | 
    
         
            +
                TEST_RB_VAL_FOR_CLASS(val, klass_for_hash)
         
     | 
| 
      
 557 
     | 
    
         
            +
                if (ret) {
         
     | 
| 
      
 558 
     | 
    
         
            +
                  bool flag = true;
         
     | 
| 
      
 559 
     | 
    
         
            +
                  HASH_FOREACH_BEGIN(val, &flag, type->keyType, type->elementType,
         
     | 
| 
      
 560 
     | 
    
         
            +
                                     &recursive)
         
     | 
| 
      
 561 
     | 
    
         
            +
                  bool *flag = (bool *)argv[0], *recursive = (bool *)argv[3];
         
     | 
| 
      
 562 
     | 
    
         
            +
                  FieldInfo *field_info_key = (FieldInfo *)argv[1];
         
     | 
| 
      
 563 
     | 
    
         
            +
                  FieldInfo *field_info_value = (FieldInfo *)argv[2];
         
     | 
| 
      
 564 
     | 
    
         
            +
                  if (!validateAny(field_info_key, k, *recursive) ||
         
     | 
| 
      
 565 
     | 
    
         
            +
                      !validateAny(field_info_value, v, *recursive)) {
         
     | 
| 
      
 566 
     | 
    
         
            +
                    *flag = false;
         
     | 
| 
      
 567 
     | 
    
         
            +
                    HASH_FOREACH_ABORT()
         
     | 
| 
      
 568 
     | 
    
         
            +
                  }
         
     | 
| 
      
 569 
     | 
    
         
            +
                  HASH_FOREACH_RET()
         
     | 
| 
      
 570 
     | 
    
         
            +
                  HASH_FOREACH_END()
         
     | 
| 
      
 571 
     | 
    
         
            +
                }
         
     | 
| 
      
 572 
     | 
    
         
            +
                break;
         
     | 
| 
      
 573 
     | 
    
         
            +
              }
         
     | 
| 
      
 574 
     | 
    
         
            +
             
     | 
| 
      
 575 
     | 
    
         
            +
              default: {
         
     | 
| 
      
 576 
     | 
    
         
            +
                rb_raise(SparsamUnknownTypeException, "Unknown type received.");
         
     | 
| 
      
 577 
     | 
    
         
            +
                ret = false;
         
     | 
| 
      
 578 
     | 
    
         
            +
                break;
         
     | 
| 
      
 579 
     | 
    
         
            +
              }
         
     | 
| 
      
 580 
     | 
    
         
            +
              }
         
     | 
| 
      
 581 
     | 
    
         
            +
              return ret;
         
     | 
| 
      
 582 
     | 
    
         
            +
            }
         
     | 
| 
      
 583 
     | 
    
         
            +
            #undef HANDLE_TYPE
         
     | 
| 
      
 584 
     | 
    
         
            +
            #undef TEST_RB_VAL_FOR_CLASS
         
     | 
| 
      
 585 
     | 
    
         
            +
             
     | 
| 
      
 586 
     | 
    
         
            +
            bool validateStruct(VALUE klass, VALUE data, bool validateContainerTypes,
         
     | 
| 
      
 587 
     | 
    
         
            +
                                bool recursive) {
         
     | 
| 
      
 588 
     | 
    
         
            +
              if (!RTEST(rb_obj_is_kind_of(data, klass))) {
         
     | 
| 
      
 589 
     | 
    
         
            +
                rb_raise(SparsamTypeMismatchError, "Wrong type of struct given for data");
         
     | 
| 
      
 590 
     | 
    
         
            +
                return false;
         
     | 
| 
      
 591 
     | 
    
         
            +
              }
         
     | 
| 
      
 592 
     | 
    
         
            +
              auto fields = FindOrCreateFieldInfoMap(klass);
         
     | 
| 
      
 593 
     | 
    
         
            +
              for (auto const &entry : *fields) {
         
     | 
| 
      
 594 
     | 
    
         
            +
                VALUE val = rb_ivar_get(data, entry.second->ivarName);
         
     | 
| 
      
 595 
     | 
    
         
            +
                if (NIL_P(val)) {
         
     | 
| 
      
 596 
     | 
    
         
            +
                  if (!entry.second->isOptional) {
         
     | 
| 
      
 597 
     | 
    
         
            +
                    rb_raise(SparsamMissingMandatory, "Missing: fieldID %d", entry.first);
         
     | 
| 
      
 598 
     | 
    
         
            +
                    return false;
         
     | 
| 
      
 599 
     | 
    
         
            +
                  }
         
     | 
| 
      
 600 
     | 
    
         
            +
                  continue;
         
     | 
| 
      
 601 
     | 
    
         
            +
                }
         
     | 
| 
      
 602 
     | 
    
         
            +
                if (validateContainerTypes && !validateAny(entry.second, val, recursive)) {
         
     | 
| 
      
 603 
     | 
    
         
            +
                  return false;
         
     | 
| 
      
 604 
     | 
    
         
            +
                }
         
     | 
| 
      
 605 
     | 
    
         
            +
              }
         
     | 
| 
      
 606 
     | 
    
         
            +
              return true;
         
     | 
| 
      
 607 
     | 
    
         
            +
            }
         
     | 
| 
      
 608 
     | 
    
         
            +
             
     | 
| 
      
 609 
     | 
    
         
            +
            VALUE serializer_validate(VALUE self, VALUE klass, VALUE data,
         
     | 
| 
      
 610 
     | 
    
         
            +
                                      VALUE strictness) {
         
     | 
| 
      
 611 
     | 
    
         
            +
              switch (static_cast<ValidateStrictness>(FIX2INT(strictness))) {
         
     | 
| 
      
 612 
     | 
    
         
            +
              case strict: {
         
     | 
| 
      
 613 
     | 
    
         
            +
                return validateStruct(klass, data, true, false) ? Qtrue : Qfalse;
         
     | 
| 
      
 614 
     | 
    
         
            +
              }
         
     | 
| 
      
 615 
     | 
    
         
            +
              case recursive: {
         
     | 
| 
      
 616 
     | 
    
         
            +
                return validateStruct(klass, data, true, true) ? Qtrue : Qfalse;
         
     | 
| 
      
 617 
     | 
    
         
            +
              }
         
     | 
| 
      
 618 
     | 
    
         
            +
              default: {
         
     | 
| 
      
 619 
     | 
    
         
            +
                return validateStruct(klass, data, false, false) ? Qtrue : Qfalse;
         
     | 
| 
      
 620 
     | 
    
         
            +
              }
         
     | 
| 
      
 621 
     | 
    
         
            +
              }
         
     | 
| 
      
 622 
     | 
    
         
            +
            }
         
     | 
| 
      
 623 
     | 
    
         
            +
             
     | 
| 
      
 624 
     | 
    
         
            +
            #define R_FIX_TO_TTYPE(x) (static_cast<TType>(FIX2INT(x)))
         
     | 
| 
      
 625 
     | 
    
         
            +
             
     | 
| 
      
 626 
     | 
    
         
            +
            FieldInfoMap *FindOrCreateFieldInfoMap(VALUE klass) {
         
     | 
| 
      
 627 
     | 
    
         
            +
              auto iter = klassCache.find(klass);
         
     | 
| 
      
 628 
     | 
    
         
            +
              if (iter == klassCache.end()) {
         
     | 
| 
      
 629 
     | 
    
         
            +
                if (RTEST(rb_class_inherited_p(klass, klass_for_union))) {
         
     | 
| 
      
 630 
     | 
    
         
            +
                  unions.insert(klass);
         
     | 
| 
      
 631 
     | 
    
         
            +
                }
         
     | 
| 
      
 632 
     | 
    
         
            +
                auto ret = CreateFieldInfoMap(klass);
         
     | 
| 
      
 633 
     | 
    
         
            +
                klassCache[klass] = ret;
         
     | 
| 
      
 634 
     | 
    
         
            +
                return ret;
         
     | 
| 
      
 635 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 636 
     | 
    
         
            +
                return iter->second;
         
     | 
| 
      
 637 
     | 
    
         
            +
              }
         
     | 
| 
      
 638 
     | 
    
         
            +
            }
         
     | 
| 
      
 639 
     | 
    
         
            +
             
     | 
| 
      
 640 
     | 
    
         
            +
            ID field_name_to_ivar_id(VALUE str_name) {
         
     | 
| 
      
 641 
     | 
    
         
            +
              if (str_name != Qnil) {
         
     | 
| 
      
 642 
     | 
    
         
            +
                return rb_intern_str(rb_str_concat(rb_str_new2("@"), str_name));
         
     | 
| 
      
 643 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 644 
     | 
    
         
            +
                return NULL;
         
     | 
| 
      
 645 
     | 
    
         
            +
              }
         
     | 
| 
      
 646 
     | 
    
         
            +
            }
         
     | 
| 
      
 647 
     | 
    
         
            +
             
     | 
| 
      
 648 
     | 
    
         
            +
            VALUE field_name_to_sym(VALUE str_name) {
         
     | 
| 
      
 649 
     | 
    
         
            +
              if (str_name != Qnil) {
         
     | 
| 
      
 650 
     | 
    
         
            +
                return ID2SYM(rb_intern_str(str_name));
         
     | 
| 
      
 651 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 652 
     | 
    
         
            +
                return NULL;
         
     | 
| 
      
 653 
     | 
    
         
            +
              }
         
     | 
| 
      
 654 
     | 
    
         
            +
            }
         
     | 
| 
      
 655 
     | 
    
         
            +
             
     | 
| 
      
 656 
     | 
    
         
            +
            // each FieldInfoMap has multiple FieldInfos
         
     | 
| 
      
 657 
     | 
    
         
            +
            FieldInfo *CreateFieldInfo(VALUE field_map_entry) {
         
     | 
| 
      
 658 
     | 
    
         
            +
              FieldInfo *fieldInfo = new FieldInfo();
         
     | 
| 
      
 659 
     | 
    
         
            +
              fieldInfo->ftype =
         
     | 
| 
      
 660 
     | 
    
         
            +
                  R_FIX_TO_TTYPE(rb_hash_aref(field_map_entry, sym_for_type));
         
     | 
| 
      
 661 
     | 
    
         
            +
              fieldInfo->isOptional =
         
     | 
| 
      
 662 
     | 
    
         
            +
                  RTEST(rb_hash_aref(field_map_entry, sym_for_optional));
         
     | 
| 
      
 663 
     | 
    
         
            +
              fieldInfo->ivarName = field_name_to_ivar_id(rb_hash_aref(field_map_entry, sym_for_name));
         
     | 
| 
      
 664 
     | 
    
         
            +
              fieldInfo->symName = field_name_to_sym(rb_hash_aref(field_map_entry, sym_for_name));
         
     | 
| 
      
 665 
     | 
    
         
            +
              switch (fieldInfo->ftype) {
         
     | 
| 
      
 666 
     | 
    
         
            +
              case protocol::T_STRING: {
         
     | 
| 
      
 667 
     | 
    
         
            +
                if (RTEST(rb_hash_aref(field_map_entry, sym_for_binary))) {
         
     | 
| 
      
 668 
     | 
    
         
            +
                  fieldInfo->isBinaryString = true;
         
     | 
| 
      
 669 
     | 
    
         
            +
                }
         
     | 
| 
      
 670 
     | 
    
         
            +
                break;
         
     | 
| 
      
 671 
     | 
    
         
            +
              }
         
     | 
| 
      
 672 
     | 
    
         
            +
              case protocol::T_STRUCT: {
         
     | 
| 
      
 673 
     | 
    
         
            +
                fieldInfo->klass = rb_hash_aref(field_map_entry, sym_for_class);
         
     | 
| 
      
 674 
     | 
    
         
            +
                break;
         
     | 
| 
      
 675 
     | 
    
         
            +
              }
         
     | 
| 
      
 676 
     | 
    
         
            +
              case protocol::T_LIST:
         
     | 
| 
      
 677 
     | 
    
         
            +
              case protocol::T_SET: {
         
     | 
| 
      
 678 
     | 
    
         
            +
                fieldInfo->elementType =
         
     | 
| 
      
 679 
     | 
    
         
            +
                    CreateFieldInfo(rb_hash_aref(field_map_entry, sym_for_element));
         
     | 
| 
      
 680 
     | 
    
         
            +
                break;
         
     | 
| 
      
 681 
     | 
    
         
            +
              }
         
     | 
| 
      
 682 
     | 
    
         
            +
              case protocol::T_MAP: {
         
     | 
| 
      
 683 
     | 
    
         
            +
                fieldInfo->keyType =
         
     | 
| 
      
 684 
     | 
    
         
            +
                    CreateFieldInfo(rb_hash_aref(field_map_entry, sym_for_key));
         
     | 
| 
      
 685 
     | 
    
         
            +
                fieldInfo->elementType =
         
     | 
| 
      
 686 
     | 
    
         
            +
                    CreateFieldInfo(rb_hash_aref(field_map_entry, sym_for_value));
         
     | 
| 
      
 687 
     | 
    
         
            +
                break;
         
     | 
| 
      
 688 
     | 
    
         
            +
              }
         
     | 
| 
      
 689 
     | 
    
         
            +
              default:
         
     | 
| 
      
 690 
     | 
    
         
            +
                break;
         
     | 
| 
      
 691 
     | 
    
         
            +
              }
         
     | 
| 
      
 692 
     | 
    
         
            +
              return fieldInfo;
         
     | 
| 
      
 693 
     | 
    
         
            +
            }
         
     | 
| 
      
 694 
     | 
    
         
            +
             
     | 
| 
      
 695 
     | 
    
         
            +
            // each klass has a FieldInfoMap
         
     | 
| 
      
 696 
     | 
    
         
            +
            FieldInfoMap *CreateFieldInfoMap(VALUE klass) {
         
     | 
| 
      
 697 
     | 
    
         
            +
              FieldInfoMap *fieldMap = new FieldInfoMap();
         
     | 
| 
      
 698 
     | 
    
         
            +
              VALUE field_map = rb_const_get_at(klass, intern_for_FIELDS);
         
     | 
| 
      
 699 
     | 
    
         
            +
             
     | 
| 
      
 700 
     | 
    
         
            +
              HASH_FOREACH_BEGIN(field_map, fieldMap)
         
     | 
| 
      
 701 
     | 
    
         
            +
              FieldInfoMap *fieldMap = (FieldInfoMap *)argv[0];
         
     | 
| 
      
 702 
     | 
    
         
            +
              (*fieldMap)[FIX2INT(k)] = CreateFieldInfo(v);
         
     | 
| 
      
 703 
     | 
    
         
            +
              HASH_FOREACH_END()
         
     | 
| 
      
 704 
     | 
    
         
            +
              return fieldMap;
         
     | 
| 
      
 705 
     | 
    
         
            +
            }
         
     | 
| 
      
 706 
     | 
    
         
            +
             
     | 
| 
      
 707 
     | 
    
         
            +
            VALUE cache_fields(VALUE self, VALUE klass) {
         
     | 
| 
      
 708 
     | 
    
         
            +
              FindOrCreateFieldInfoMap(klass);
         
     | 
| 
      
 709 
     | 
    
         
            +
              return Qnil;
         
     | 
| 
      
 710 
     | 
    
         
            +
            }
         
     | 
| 
      
 711 
     | 
    
         
            +
             
     | 
| 
      
 712 
     | 
    
         
            +
            #undef HASH_FOREACH_BEGIN
         
     | 
| 
      
 713 
     | 
    
         
            +
            #undef HASH_FOEACH_RET
         
     | 
| 
      
 714 
     | 
    
         
            +
            #undef HASH_FOREACH_END
         
     | 
| 
      
 715 
     | 
    
         
            +
             
     | 
| 
      
 716 
     | 
    
         
            +
            #undef R_FIX_TO_TTYPE
         
     |