tiny_thrift 1.0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/README +43 -0
  3. data/benchmark/Benchmark.thrift +24 -0
  4. data/benchmark/benchmark.rb +271 -0
  5. data/benchmark/client.rb +74 -0
  6. data/benchmark/server.rb +82 -0
  7. data/benchmark/thin_server.rb +44 -0
  8. data/ext/binary_protocol_accelerated.c +460 -0
  9. data/ext/binary_protocol_accelerated.h +20 -0
  10. data/ext/bytes.c +36 -0
  11. data/ext/bytes.h +31 -0
  12. data/ext/compact_protocol.c +635 -0
  13. data/ext/compact_protocol.h +20 -0
  14. data/ext/constants.h +96 -0
  15. data/ext/extconf.rb +32 -0
  16. data/ext/macros.h +41 -0
  17. data/ext/memory_buffer.c +134 -0
  18. data/ext/memory_buffer.h +20 -0
  19. data/ext/protocol.c +0 -0
  20. data/ext/protocol.h +0 -0
  21. data/ext/strlcpy.c +41 -0
  22. data/ext/strlcpy.h +34 -0
  23. data/ext/struct.c +688 -0
  24. data/ext/struct.h +25 -0
  25. data/ext/thrift_native.c +195 -0
  26. data/lib/thrift.rb +66 -0
  27. data/lib/thrift/bytes.rb +131 -0
  28. data/lib/thrift/client.rb +62 -0
  29. data/lib/thrift/core_ext.rb +23 -0
  30. data/lib/thrift/core_ext/fixnum.rb +29 -0
  31. data/lib/thrift/exceptions.rb +87 -0
  32. data/lib/thrift/processor.rb +57 -0
  33. data/lib/thrift/protocol/base_protocol.rb +377 -0
  34. data/lib/thrift/protocol/binary_protocol.rb +237 -0
  35. data/lib/thrift/protocol/binary_protocol_accelerated.rb +39 -0
  36. data/lib/thrift/protocol/compact_protocol.rb +434 -0
  37. data/lib/thrift/protocol/json_protocol.rb +769 -0
  38. data/lib/thrift/serializer/deserializer.rb +33 -0
  39. data/lib/thrift/serializer/serializer.rb +34 -0
  40. data/lib/thrift/server/base_server.rb +31 -0
  41. data/lib/thrift/server/mongrel_http_server.rb +60 -0
  42. data/lib/thrift/server/nonblocking_server.rb +305 -0
  43. data/lib/thrift/server/simple_server.rb +43 -0
  44. data/lib/thrift/server/thin_http_server.rb +91 -0
  45. data/lib/thrift/server/thread_pool_server.rb +75 -0
  46. data/lib/thrift/server/threaded_server.rb +47 -0
  47. data/lib/thrift/struct.rb +237 -0
  48. data/lib/thrift/struct_union.rb +192 -0
  49. data/lib/thrift/thrift_native.rb +24 -0
  50. data/lib/thrift/transport/base_server_transport.rb +37 -0
  51. data/lib/thrift/transport/base_transport.rb +109 -0
  52. data/lib/thrift/transport/buffered_transport.rb +114 -0
  53. data/lib/thrift/transport/framed_transport.rb +117 -0
  54. data/lib/thrift/transport/http_client_transport.rb +56 -0
  55. data/lib/thrift/transport/io_stream_transport.rb +39 -0
  56. data/lib/thrift/transport/memory_buffer_transport.rb +125 -0
  57. data/lib/thrift/transport/server_socket.rb +63 -0
  58. data/lib/thrift/transport/socket.rb +139 -0
  59. data/lib/thrift/transport/unix_server_socket.rb +60 -0
  60. data/lib/thrift/transport/unix_socket.rb +40 -0
  61. data/lib/thrift/types.rb +101 -0
  62. data/lib/thrift/union.rb +179 -0
  63. data/lib/tiny_thrift.rb +1 -0
  64. data/spec/ThriftSpec.thrift +183 -0
  65. data/spec/base_protocol_spec.rb +217 -0
  66. data/spec/base_transport_spec.rb +350 -0
  67. data/spec/binary_protocol_accelerated_spec.rb +42 -0
  68. data/spec/binary_protocol_spec.rb +66 -0
  69. data/spec/binary_protocol_spec_shared.rb +455 -0
  70. data/spec/bytes_spec.rb +160 -0
  71. data/spec/client_spec.rb +99 -0
  72. data/spec/compact_protocol_spec.rb +143 -0
  73. data/spec/exception_spec.rb +141 -0
  74. data/spec/http_client_spec.rb +120 -0
  75. data/spec/json_protocol_spec.rb +513 -0
  76. data/spec/nonblocking_server_spec.rb +263 -0
  77. data/spec/processor_spec.rb +80 -0
  78. data/spec/serializer_spec.rb +67 -0
  79. data/spec/server_socket_spec.rb +79 -0
  80. data/spec/server_spec.rb +147 -0
  81. data/spec/socket_spec.rb +61 -0
  82. data/spec/socket_spec_shared.rb +104 -0
  83. data/spec/spec_helper.rb +61 -0
  84. data/spec/struct_nested_containers_spec.rb +191 -0
  85. data/spec/struct_spec.rb +293 -0
  86. data/spec/thin_http_server_spec.rb +141 -0
  87. data/spec/types_spec.rb +115 -0
  88. data/spec/union_spec.rb +203 -0
  89. data/spec/unix_socket_spec.rb +107 -0
  90. metadata +313 -0
@@ -0,0 +1,20 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+
20
+ void Init_compact_protocol();
@@ -0,0 +1,96 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+
20
+ extern int TTYPE_STOP;
21
+ extern int TTYPE_BOOL;
22
+ extern int TTYPE_BYTE;
23
+ extern int TTYPE_I16;
24
+ extern int TTYPE_I32;
25
+ extern int TTYPE_I64;
26
+ extern int TTYPE_DOUBLE;
27
+ extern int TTYPE_STRING;
28
+ extern int TTYPE_MAP;
29
+ extern int TTYPE_SET;
30
+ extern int TTYPE_LIST;
31
+ extern int TTYPE_STRUCT;
32
+
33
+ extern ID validate_method_id;
34
+ extern ID write_struct_begin_method_id;
35
+ extern ID write_struct_end_method_id;
36
+ extern ID write_field_begin_method_id;
37
+ extern ID write_field_end_method_id;
38
+ extern ID write_boolean_method_id;
39
+ extern ID write_byte_method_id;
40
+ extern ID write_i16_method_id;
41
+ extern ID write_i32_method_id;
42
+ extern ID write_i64_method_id;
43
+ extern ID write_double_method_id;
44
+ extern ID write_string_method_id;
45
+ extern ID write_map_begin_method_id;
46
+ extern ID write_map_end_method_id;
47
+ extern ID write_list_begin_method_id;
48
+ extern ID write_list_end_method_id;
49
+ extern ID write_set_begin_method_id;
50
+ extern ID write_set_end_method_id;
51
+ extern ID read_bool_method_id;
52
+ extern ID read_byte_method_id;
53
+ extern ID read_i16_method_id;
54
+ extern ID read_i32_method_id;
55
+ extern ID read_i64_method_id;
56
+ extern ID read_string_method_id;
57
+ extern ID read_double_method_id;
58
+ extern ID read_map_begin_method_id;
59
+ extern ID read_map_end_method_id;
60
+ extern ID read_list_begin_method_id;
61
+ extern ID read_list_end_method_id;
62
+ extern ID read_set_begin_method_id;
63
+ extern ID read_set_end_method_id;
64
+ extern ID read_struct_begin_method_id;
65
+ extern ID read_struct_end_method_id;
66
+ extern ID read_field_begin_method_id;
67
+ extern ID read_field_end_method_id;
68
+ extern ID keys_method_id;
69
+ extern ID entries_method_id;
70
+ extern ID write_field_stop_method_id;
71
+ extern ID skip_method_id;
72
+ extern ID write_method_id;
73
+ extern ID read_all_method_id;
74
+ extern ID read_into_buffer_method_id;
75
+ extern ID force_binary_encoding_id;
76
+ extern ID convert_to_utf8_byte_buffer_id;
77
+ extern ID convert_to_string_id;
78
+
79
+ extern ID fields_const_id;
80
+ extern ID transport_ivar_id;
81
+ extern ID strict_read_ivar_id;
82
+ extern ID strict_write_ivar_id;
83
+
84
+ extern VALUE type_sym;
85
+ extern VALUE name_sym;
86
+ extern VALUE key_sym;
87
+ extern VALUE value_sym;
88
+ extern VALUE element_sym;
89
+ extern VALUE class_sym;
90
+
91
+ extern VALUE rb_cSet;
92
+ extern VALUE thrift_module;
93
+ extern VALUE thrift_types_module;
94
+ extern VALUE thrift_bytes_module;
95
+ extern VALUE class_thrift_protocol;
96
+ extern VALUE protocol_exception_class;
@@ -0,0 +1,32 @@
1
+ #
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ #
19
+
20
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
21
+ File.open('Makefile', 'w'){|f| f.puts "all:\n\ninstall:\n" }
22
+ else
23
+ require 'mkmf'
24
+
25
+ $ARCH_FLAGS = Config::CONFIG['CFLAGS'].scan( /(-arch )(\S+)/ ).map{|x,y| x + y + ' ' }.join('')
26
+
27
+ $CFLAGS = "-fsigned-char -g -O2 -Wall -Werror " + $ARCH_FLAGS
28
+
29
+ have_func("strlcpy", "string.h")
30
+
31
+ create_makefile 'thrift_native'
32
+ end
@@ -0,0 +1,41 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+
20
+ #define GET_TRANSPORT(obj) rb_ivar_get(obj, transport_ivar_id)
21
+ #define GET_STRICT_READ(obj) rb_ivar_get(obj, strict_read_ivar_id)
22
+ #define GET_STRICT_WRITE(obj) rb_ivar_get(obj, strict_write_ivar_id)
23
+ #define WRITE(obj, data, length) rb_funcall(obj, write_method_id, 1, rb_str_new(data, length))
24
+ #define CHECK_NIL(obj) if (NIL_P(obj)) { rb_raise(rb_eStandardError, "nil argument not allowed!");}
25
+ #define READ(obj, length) rb_funcall(GET_TRANSPORT(obj), read_all_method_id, 1, INT2FIX(length))
26
+
27
+ #ifndef RFLOAT_VALUE
28
+ # define RFLOAT_VALUE(v) RFLOAT(rb_Float(v))->value
29
+ #endif
30
+
31
+ #ifndef RSTRING_LEN
32
+ # define RSTRING_LEN(v) RSTRING(rb_String(v))->len
33
+ #endif
34
+
35
+ #ifndef RSTRING_PTR
36
+ # define RSTRING_PTR(v) RSTRING(rb_String(v))->ptr
37
+ #endif
38
+
39
+ #ifndef RARRAY_LEN
40
+ # define RARRAY_LEN(v) RARRAY(rb_Array(v))->len
41
+ #endif
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+
20
+ #include <ruby.h>
21
+ #include <constants.h>
22
+ #include <bytes.h>
23
+ #include <macros.h>
24
+
25
+ ID buf_ivar_id;
26
+ ID index_ivar_id;
27
+
28
+ ID slice_method_id;
29
+
30
+ int GARBAGE_BUFFER_SIZE;
31
+
32
+ #define GET_BUF(self) rb_ivar_get(self, buf_ivar_id)
33
+
34
+ VALUE rb_thrift_memory_buffer_write(VALUE self, VALUE str);
35
+ VALUE rb_thrift_memory_buffer_read(VALUE self, VALUE length_value);
36
+ VALUE rb_thrift_memory_buffer_read_byte(VALUE self);
37
+ VALUE rb_thrift_memory_buffer_read_into_buffer(VALUE self, VALUE buffer_value, VALUE size_value);
38
+
39
+ VALUE rb_thrift_memory_buffer_write(VALUE self, VALUE str) {
40
+ VALUE buf = GET_BUF(self);
41
+ str = force_binary_encoding(str);
42
+ rb_str_buf_cat(buf, StringValuePtr(str), RSTRING_LEN(str));
43
+ return Qnil;
44
+ }
45
+
46
+ VALUE rb_thrift_memory_buffer_read(VALUE self, VALUE length_value) {
47
+ int length = FIX2INT(length_value);
48
+
49
+ VALUE index_value = rb_ivar_get(self, index_ivar_id);
50
+ int index = FIX2INT(index_value);
51
+
52
+ VALUE buf = GET_BUF(self);
53
+ VALUE data = rb_funcall(buf, slice_method_id, 2, index_value, length_value);
54
+
55
+ index += length;
56
+ if (index > RSTRING_LEN(buf)) {
57
+ index = RSTRING_LEN(buf);
58
+ }
59
+ if (index >= GARBAGE_BUFFER_SIZE) {
60
+ rb_ivar_set(self, buf_ivar_id, rb_funcall(buf, slice_method_id, 2, INT2FIX(index), INT2FIX(RSTRING_LEN(buf) - 1)));
61
+ index = 0;
62
+ }
63
+ rb_ivar_set(self, index_ivar_id, INT2FIX(index));
64
+
65
+ if (RSTRING_LEN(data) < length) {
66
+ rb_raise(rb_eEOFError, "Not enough bytes remain in memory buffer");
67
+ }
68
+
69
+ return data;
70
+ }
71
+
72
+ VALUE rb_thrift_memory_buffer_read_byte(VALUE self) {
73
+ VALUE index_value = rb_ivar_get(self, index_ivar_id);
74
+ int index = FIX2INT(index_value);
75
+
76
+ VALUE buf = GET_BUF(self);
77
+ if (index >= RSTRING_LEN(buf)) {
78
+ rb_raise(rb_eEOFError, "Not enough bytes remain in memory buffer");
79
+ }
80
+ char byte = RSTRING_PTR(buf)[index++];
81
+
82
+ if (index >= GARBAGE_BUFFER_SIZE) {
83
+ rb_ivar_set(self, buf_ivar_id, rb_funcall(buf, slice_method_id, 2, INT2FIX(index), INT2FIX(RSTRING_LEN(buf) - 1)));
84
+ index = 0;
85
+ }
86
+ rb_ivar_set(self, index_ivar_id, INT2FIX(index));
87
+
88
+ int result = (int) byte;
89
+ return INT2FIX(result);
90
+ }
91
+
92
+ VALUE rb_thrift_memory_buffer_read_into_buffer(VALUE self, VALUE buffer_value, VALUE size_value) {
93
+ int i = 0;
94
+ int size = FIX2INT(size_value);
95
+ int index;
96
+ VALUE buf = GET_BUF(self);
97
+
98
+ index = FIX2INT(rb_ivar_get(self, index_ivar_id));
99
+ while (i < size) {
100
+ if (index >= RSTRING_LEN(buf)) {
101
+ rb_raise(rb_eEOFError, "Not enough bytes remain in memory buffer");
102
+ }
103
+ char byte = RSTRING_PTR(buf)[index++];
104
+
105
+ if (i >= RSTRING_LEN(buffer_value)) {
106
+ rb_raise(rb_eIndexError, "index %d out of string", i);
107
+ }
108
+ ((char*)RSTRING_PTR(buffer_value))[i] = byte;
109
+ i++;
110
+ }
111
+
112
+ if (index >= GARBAGE_BUFFER_SIZE) {
113
+ rb_ivar_set(self, buf_ivar_id, rb_funcall(buf, slice_method_id, 2, INT2FIX(index), INT2FIX(RSTRING_LEN(buf) - 1)));
114
+ index = 0;
115
+ }
116
+ rb_ivar_set(self, index_ivar_id, INT2FIX(index));
117
+
118
+ return INT2FIX(i);
119
+ }
120
+
121
+ void Init_memory_buffer() {
122
+ VALUE thrift_memory_buffer_class = rb_const_get(thrift_module, rb_intern("MemoryBufferTransport"));
123
+ rb_define_method(thrift_memory_buffer_class, "write", rb_thrift_memory_buffer_write, 1);
124
+ rb_define_method(thrift_memory_buffer_class, "read", rb_thrift_memory_buffer_read, 1);
125
+ rb_define_method(thrift_memory_buffer_class, "read_byte", rb_thrift_memory_buffer_read_byte, 0);
126
+ rb_define_method(thrift_memory_buffer_class, "read_into_buffer", rb_thrift_memory_buffer_read_into_buffer, 2);
127
+
128
+ buf_ivar_id = rb_intern("@buf");
129
+ index_ivar_id = rb_intern("@index");
130
+
131
+ slice_method_id = rb_intern("slice");
132
+
133
+ GARBAGE_BUFFER_SIZE = FIX2INT(rb_const_get(thrift_memory_buffer_class, rb_intern("GARBAGE_BUFFER_SIZE")));
134
+ }
@@ -0,0 +1,20 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+
20
+ void Init_memory_buffer();
File without changes
File without changes
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+
20
+ #include "strlcpy.h"
21
+
22
+ #ifndef HAVE_STRLCPY
23
+ #define HAVE_STRLCPY
24
+ size_t
25
+ strlcpy (char *dst, const char *src, size_t dst_sz)
26
+ {
27
+ size_t n;
28
+
29
+ for (n = 0; n < dst_sz; n++) {
30
+ if ((*dst++ = *src++) == '\0')
31
+ break;
32
+ }
33
+
34
+ if (n < dst_sz)
35
+ return n;
36
+ if (n > 0)
37
+ *(dst - 1) = '\0';
38
+ return n + strlen (src);
39
+ }
40
+ #endif
41
+
@@ -0,0 +1,34 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+
20
+ #include <sys/types.h>
21
+ #include <string.h>
22
+
23
+ #ifndef __has_builtin
24
+ #define __has_builtin(x) 0
25
+ #endif
26
+
27
+ #ifndef HAVE_STRLCPY
28
+ size_t strlcpy (char *dst, const char *src, size_t dst_sz);
29
+ #else
30
+ #if !__has_builtin(strlcpy)
31
+ extern size_t strlcpy(char *, const char *, size_t);
32
+ #endif
33
+ #endif
34
+
@@ -0,0 +1,688 @@
1
+ /**
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+
20
+ #include "struct.h"
21
+ #include "constants.h"
22
+ #include "macros.h"
23
+ #include "strlcpy.h"
24
+
25
+ VALUE thrift_union_class;
26
+
27
+ ID setfield_id;
28
+ ID setvalue_id;
29
+
30
+ ID to_s_method_id;
31
+ ID name_to_id_method_id;
32
+ static ID sorted_field_ids_method_id;
33
+
34
+ #define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET)
35
+ #define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id)
36
+
37
+ //-------------------------------------------
38
+ // Writing section
39
+ //-------------------------------------------
40
+
41
+ // default fn pointers for protocol stuff here
42
+
43
+ VALUE default_write_bool(VALUE protocol, VALUE value) {
44
+ rb_funcall(protocol, write_boolean_method_id, 1, value);
45
+ return Qnil;
46
+ }
47
+
48
+ VALUE default_write_byte(VALUE protocol, VALUE value) {
49
+ rb_funcall(protocol, write_byte_method_id, 1, value);
50
+ return Qnil;
51
+ }
52
+
53
+ VALUE default_write_i16(VALUE protocol, VALUE value) {
54
+ rb_funcall(protocol, write_i16_method_id, 1, value);
55
+ return Qnil;
56
+ }
57
+
58
+ VALUE default_write_i32(VALUE protocol, VALUE value) {
59
+ rb_funcall(protocol, write_i32_method_id, 1, value);
60
+ return Qnil;
61
+ }
62
+
63
+ VALUE default_write_i64(VALUE protocol, VALUE value) {
64
+ rb_funcall(protocol, write_i64_method_id, 1, value);
65
+ return Qnil;
66
+ }
67
+
68
+ VALUE default_write_double(VALUE protocol, VALUE value) {
69
+ rb_funcall(protocol, write_double_method_id, 1, value);
70
+ return Qnil;
71
+ }
72
+
73
+ VALUE default_write_string(VALUE protocol, VALUE value) {
74
+ rb_funcall(protocol, write_string_method_id, 1, value);
75
+ return Qnil;
76
+ }
77
+
78
+ VALUE default_write_list_begin(VALUE protocol, VALUE etype, VALUE length) {
79
+ rb_funcall(protocol, write_list_begin_method_id, 2, etype, length);
80
+ return Qnil;
81
+ }
82
+
83
+ VALUE default_write_list_end(VALUE protocol) {
84
+ rb_funcall(protocol, write_list_end_method_id, 0);
85
+ return Qnil;
86
+ }
87
+
88
+ VALUE default_write_set_begin(VALUE protocol, VALUE etype, VALUE length) {
89
+ rb_funcall(protocol, write_set_begin_method_id, 2, etype, length);
90
+ return Qnil;
91
+ }
92
+
93
+ VALUE default_write_set_end(VALUE protocol) {
94
+ rb_funcall(protocol, write_set_end_method_id, 0);
95
+ return Qnil;
96
+ }
97
+
98
+ VALUE default_write_map_begin(VALUE protocol, VALUE ktype, VALUE vtype, VALUE length) {
99
+ rb_funcall(protocol, write_map_begin_method_id, 3, ktype, vtype, length);
100
+ return Qnil;
101
+ }
102
+
103
+ VALUE default_write_map_end(VALUE protocol) {
104
+ rb_funcall(protocol, write_map_end_method_id, 0);
105
+ return Qnil;
106
+ }
107
+
108
+ VALUE default_write_struct_begin(VALUE protocol, VALUE struct_name) {
109
+ rb_funcall(protocol, write_struct_begin_method_id, 1, struct_name);
110
+ return Qnil;
111
+ }
112
+
113
+ VALUE default_write_struct_end(VALUE protocol) {
114
+ rb_funcall(protocol, write_struct_end_method_id, 0);
115
+ return Qnil;
116
+ }
117
+
118
+ VALUE default_write_field_begin(VALUE protocol, VALUE name, VALUE type, VALUE id) {
119
+ rb_funcall(protocol, write_field_begin_method_id, 3, name, type, id);
120
+ return Qnil;
121
+ }
122
+
123
+ VALUE default_write_field_end(VALUE protocol) {
124
+ rb_funcall(protocol, write_field_end_method_id, 0);
125
+ return Qnil;
126
+ }
127
+
128
+ VALUE default_write_field_stop(VALUE protocol) {
129
+ rb_funcall(protocol, write_field_stop_method_id, 0);
130
+ return Qnil;
131
+ }
132
+
133
+ VALUE default_read_field_begin(VALUE protocol) {
134
+ return rb_funcall(protocol, read_field_begin_method_id, 0);
135
+ }
136
+
137
+ VALUE default_read_field_end(VALUE protocol) {
138
+ return rb_funcall(protocol, read_field_end_method_id, 0);
139
+ }
140
+
141
+ VALUE default_read_map_begin(VALUE protocol) {
142
+ return rb_funcall(protocol, read_map_begin_method_id, 0);
143
+ }
144
+
145
+ VALUE default_read_map_end(VALUE protocol) {
146
+ return rb_funcall(protocol, read_map_end_method_id, 0);
147
+ }
148
+
149
+ VALUE default_read_list_begin(VALUE protocol) {
150
+ return rb_funcall(protocol, read_list_begin_method_id, 0);
151
+ }
152
+
153
+ VALUE default_read_list_end(VALUE protocol) {
154
+ return rb_funcall(protocol, read_list_end_method_id, 0);
155
+ }
156
+
157
+ VALUE default_read_set_begin(VALUE protocol) {
158
+ return rb_funcall(protocol, read_set_begin_method_id, 0);
159
+ }
160
+
161
+ VALUE default_read_set_end(VALUE protocol) {
162
+ return rb_funcall(protocol, read_set_end_method_id, 0);
163
+ }
164
+
165
+ VALUE default_read_byte(VALUE protocol) {
166
+ return rb_funcall(protocol, read_byte_method_id, 0);
167
+ }
168
+
169
+ VALUE default_read_bool(VALUE protocol) {
170
+ return rb_funcall(protocol, read_bool_method_id, 0);
171
+ }
172
+
173
+ VALUE default_read_i16(VALUE protocol) {
174
+ return rb_funcall(protocol, read_i16_method_id, 0);
175
+ }
176
+
177
+ VALUE default_read_i32(VALUE protocol) {
178
+ return rb_funcall(protocol, read_i32_method_id, 0);
179
+ }
180
+
181
+ VALUE default_read_i64(VALUE protocol) {
182
+ return rb_funcall(protocol, read_i64_method_id, 0);
183
+ }
184
+
185
+ VALUE default_read_double(VALUE protocol) {
186
+ return rb_funcall(protocol, read_double_method_id, 0);
187
+ }
188
+
189
+ VALUE default_read_string(VALUE protocol) {
190
+ return rb_funcall(protocol, read_string_method_id, 0);
191
+ }
192
+
193
+ VALUE default_read_struct_begin(VALUE protocol) {
194
+ return rb_funcall(protocol, read_struct_begin_method_id, 0);
195
+ }
196
+
197
+ VALUE default_read_struct_end(VALUE protocol) {
198
+ return rb_funcall(protocol, read_struct_end_method_id, 0);
199
+ }
200
+
201
+ // end default protocol methods
202
+
203
+ static VALUE rb_thrift_union_write (VALUE self, VALUE protocol);
204
+ static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol);
205
+ static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info);
206
+
207
+ VALUE get_field_value(VALUE obj, VALUE field_name) {
208
+ char name_buf[RSTRING_LEN(field_name) + 2];
209
+
210
+ name_buf[0] = '@';
211
+ strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name) + 1);
212
+
213
+ VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
214
+
215
+ return value;
216
+ }
217
+
218
+ static void write_container(int ttype, VALUE field_info, VALUE value, VALUE protocol) {
219
+ int sz, i;
220
+
221
+ if (ttype == TTYPE_MAP) {
222
+ VALUE keys;
223
+ VALUE key;
224
+ VALUE val;
225
+
226
+ Check_Type(value, T_HASH);
227
+
228
+ VALUE key_info = rb_hash_aref(field_info, key_sym);
229
+ VALUE keytype_value = rb_hash_aref(key_info, type_sym);
230
+ int keytype = FIX2INT(keytype_value);
231
+
232
+ VALUE value_info = rb_hash_aref(field_info, value_sym);
233
+ VALUE valuetype_value = rb_hash_aref(value_info, type_sym);
234
+ int valuetype = FIX2INT(valuetype_value);
235
+
236
+ keys = rb_funcall(value, keys_method_id, 0);
237
+
238
+ sz = RARRAY_LEN(keys);
239
+
240
+ default_write_map_begin(protocol, keytype_value, valuetype_value, INT2FIX(sz));
241
+
242
+ for (i = 0; i < sz; i++) {
243
+ key = rb_ary_entry(keys, i);
244
+ val = rb_hash_aref(value, key);
245
+
246
+ if (IS_CONTAINER(keytype)) {
247
+ write_container(keytype, key_info, key, protocol);
248
+ } else {
249
+ write_anything(keytype, key, protocol, key_info);
250
+ }
251
+
252
+ if (IS_CONTAINER(valuetype)) {
253
+ write_container(valuetype, value_info, val, protocol);
254
+ } else {
255
+ write_anything(valuetype, val, protocol, value_info);
256
+ }
257
+ }
258
+
259
+ default_write_map_end(protocol);
260
+ } else if (ttype == TTYPE_LIST) {
261
+ Check_Type(value, T_ARRAY);
262
+
263
+ sz = RARRAY_LEN(value);
264
+
265
+ VALUE element_type_info = rb_hash_aref(field_info, element_sym);
266
+ VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
267
+ int element_type = FIX2INT(element_type_value);
268
+
269
+ default_write_list_begin(protocol, element_type_value, INT2FIX(sz));
270
+ for (i = 0; i < sz; ++i) {
271
+ VALUE val = rb_ary_entry(value, i);
272
+ if (IS_CONTAINER(element_type)) {
273
+ write_container(element_type, element_type_info, val, protocol);
274
+ } else {
275
+ write_anything(element_type, val, protocol, element_type_info);
276
+ }
277
+ }
278
+ default_write_list_end(protocol);
279
+ } else if (ttype == TTYPE_SET) {
280
+ VALUE items;
281
+
282
+ if (TYPE(value) == T_ARRAY) {
283
+ items = value;
284
+ } else {
285
+ if (rb_cSet == CLASS_OF(value)) {
286
+ items = rb_funcall(value, entries_method_id, 0);
287
+ } else {
288
+ Check_Type(value, T_HASH);
289
+ items = rb_funcall(value, keys_method_id, 0);
290
+ }
291
+ }
292
+
293
+ sz = RARRAY_LEN(items);
294
+
295
+ VALUE element_type_info = rb_hash_aref(field_info, element_sym);
296
+ VALUE element_type_value = rb_hash_aref(element_type_info, type_sym);
297
+ int element_type = FIX2INT(element_type_value);
298
+
299
+ default_write_set_begin(protocol, element_type_value, INT2FIX(sz));
300
+
301
+ for (i = 0; i < sz; i++) {
302
+ VALUE val = rb_ary_entry(items, i);
303
+ if (IS_CONTAINER(element_type)) {
304
+ write_container(element_type, element_type_info, val, protocol);
305
+ } else {
306
+ write_anything(element_type, val, protocol, element_type_info);
307
+ }
308
+ }
309
+
310
+ default_write_set_end(protocol);
311
+ } else {
312
+ rb_raise(rb_eNotImpError, "can't write container of type: %d", ttype);
313
+ }
314
+ }
315
+
316
+ static void write_anything(int ttype, VALUE value, VALUE protocol, VALUE field_info) {
317
+ if (ttype == TTYPE_BOOL) {
318
+ default_write_bool(protocol, value);
319
+ } else if (ttype == TTYPE_BYTE) {
320
+ default_write_byte(protocol, value);
321
+ } else if (ttype == TTYPE_I16) {
322
+ default_write_i16(protocol, value);
323
+ } else if (ttype == TTYPE_I32) {
324
+ default_write_i32(protocol, value);
325
+ } else if (ttype == TTYPE_I64) {
326
+ default_write_i64(protocol, value);
327
+ } else if (ttype == TTYPE_DOUBLE) {
328
+ default_write_double(protocol, value);
329
+ } else if (ttype == TTYPE_STRING) {
330
+ default_write_string(protocol, value);
331
+ } else if (IS_CONTAINER(ttype)) {
332
+ write_container(ttype, field_info, value, protocol);
333
+ } else if (ttype == TTYPE_STRUCT) {
334
+ if (rb_obj_is_kind_of(value, thrift_union_class)) {
335
+ rb_thrift_union_write(value, protocol);
336
+ } else {
337
+ rb_thrift_struct_write(value, protocol);
338
+ }
339
+ } else {
340
+ rb_raise(rb_eNotImpError, "Unknown type for binary_encoding: %d", ttype);
341
+ }
342
+ }
343
+
344
+ static VALUE rb_thrift_struct_write(VALUE self, VALUE protocol) {
345
+ // call validate
346
+ rb_funcall(self, validate_method_id, 0);
347
+
348
+ // write struct begin
349
+ default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
350
+
351
+ // iterate through all the fields here
352
+ VALUE struct_fields = STRUCT_FIELDS(self);
353
+ VALUE sorted_field_ids = rb_funcall(self, sorted_field_ids_method_id, 0);
354
+
355
+ int i = 0;
356
+ for (i=0; i < RARRAY_LEN(sorted_field_ids); i++) {
357
+ VALUE field_id = rb_ary_entry(sorted_field_ids, i);
358
+
359
+ VALUE field_info = rb_hash_aref(struct_fields, field_id);
360
+
361
+ VALUE ttype_value = rb_hash_aref(field_info, type_sym);
362
+ int ttype = FIX2INT(ttype_value);
363
+ VALUE field_name = rb_hash_aref(field_info, name_sym);
364
+
365
+ VALUE field_value = get_field_value(self, field_name);
366
+
367
+ if (!NIL_P(field_value)) {
368
+ default_write_field_begin(protocol, field_name, ttype_value, field_id);
369
+
370
+ write_anything(ttype, field_value, protocol, field_info);
371
+
372
+ default_write_field_end(protocol);
373
+ }
374
+ }
375
+
376
+ default_write_field_stop(protocol);
377
+
378
+ // write struct end
379
+ default_write_struct_end(protocol);
380
+
381
+ return Qnil;
382
+ }
383
+
384
+ //-------------------------------------------
385
+ // Reading section
386
+ //-------------------------------------------
387
+
388
+ static VALUE rb_thrift_union_read(VALUE self, VALUE protocol);
389
+ static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol);
390
+ static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size);
391
+ static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size);
392
+
393
+ static void set_field_value(VALUE obj, VALUE field_name, VALUE value) {
394
+ char name_buf[RSTRING_LEN(field_name) + 2];
395
+
396
+ name_buf[0] = '@';
397
+ strlcpy(&name_buf[1], RSTRING_PTR(field_name), RSTRING_LEN(field_name)+1);
398
+
399
+ rb_ivar_set(obj, rb_intern(name_buf), value);
400
+ }
401
+
402
+ // Helper method to skip the contents of a map (assumes the map header has been read).
403
+ static void skip_map_contents(VALUE protocol, VALUE key_type_value, VALUE value_type_value, int size) {
404
+ int i;
405
+ for (i = 0; i < size; i++) {
406
+ rb_funcall(protocol, skip_method_id, 1, key_type_value);
407
+ rb_funcall(protocol, skip_method_id, 1, value_type_value);
408
+ }
409
+ }
410
+
411
+ // Helper method to skip the contents of a list or set (assumes the list/set header has been read).
412
+ static void skip_list_or_set_contents(VALUE protocol, VALUE element_type_value, int size) {
413
+ int i;
414
+ for (i = 0; i < size; i++) {
415
+ rb_funcall(protocol, skip_method_id, 1, element_type_value);
416
+ }
417
+ }
418
+
419
+ static VALUE read_anything(VALUE protocol, int ttype, VALUE field_info) {
420
+ VALUE result = Qnil;
421
+
422
+ if (ttype == TTYPE_BOOL) {
423
+ result = default_read_bool(protocol);
424
+ } else if (ttype == TTYPE_BYTE) {
425
+ result = default_read_byte(protocol);
426
+ } else if (ttype == TTYPE_I16) {
427
+ result = default_read_i16(protocol);
428
+ } else if (ttype == TTYPE_I32) {
429
+ result = default_read_i32(protocol);
430
+ } else if (ttype == TTYPE_I64) {
431
+ result = default_read_i64(protocol);
432
+ } else if (ttype == TTYPE_STRING) {
433
+ result = default_read_string(protocol);
434
+ } else if (ttype == TTYPE_DOUBLE) {
435
+ result = default_read_double(protocol);
436
+ } else if (ttype == TTYPE_STRUCT) {
437
+ VALUE klass = rb_hash_aref(field_info, class_sym);
438
+ result = rb_class_new_instance(0, NULL, klass);
439
+
440
+ if (rb_obj_is_kind_of(result, thrift_union_class)) {
441
+ rb_thrift_union_read(result, protocol);
442
+ } else {
443
+ rb_thrift_struct_read(result, protocol);
444
+ }
445
+ } else if (ttype == TTYPE_MAP) {
446
+ int i;
447
+
448
+ VALUE map_header = default_read_map_begin(protocol);
449
+ int key_ttype = FIX2INT(rb_ary_entry(map_header, 0));
450
+ int value_ttype = FIX2INT(rb_ary_entry(map_header, 1));
451
+ int num_entries = FIX2INT(rb_ary_entry(map_header, 2));
452
+
453
+ // Check the declared key and value types against the expected ones and skip the map contents
454
+ // if the types don't match.
455
+ VALUE key_info = rb_hash_aref(field_info, key_sym);
456
+ VALUE value_info = rb_hash_aref(field_info, value_sym);
457
+
458
+ if (!NIL_P(key_info) && !NIL_P(value_info)) {
459
+ int specified_key_type = FIX2INT(rb_hash_aref(key_info, type_sym));
460
+ int specified_value_type = FIX2INT(rb_hash_aref(value_info, type_sym));
461
+ if (num_entries == 0 || (specified_key_type == key_ttype && specified_value_type == value_ttype)) {
462
+ result = rb_hash_new();
463
+
464
+ for (i = 0; i < num_entries; ++i) {
465
+ VALUE key, val;
466
+
467
+ key = read_anything(protocol, key_ttype, key_info);
468
+ val = read_anything(protocol, value_ttype, value_info);
469
+
470
+ rb_hash_aset(result, key, val);
471
+ }
472
+ } else {
473
+ skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
474
+ }
475
+ } else {
476
+ skip_map_contents(protocol, INT2FIX(key_ttype), INT2FIX(value_ttype), num_entries);
477
+ }
478
+
479
+ default_read_map_end(protocol);
480
+ } else if (ttype == TTYPE_LIST) {
481
+ int i;
482
+
483
+ VALUE list_header = default_read_list_begin(protocol);
484
+ int element_ttype = FIX2INT(rb_ary_entry(list_header, 0));
485
+ int num_elements = FIX2INT(rb_ary_entry(list_header, 1));
486
+
487
+ // Check the declared element type against the expected one and skip the list contents
488
+ // if the types don't match.
489
+ VALUE element_info = rb_hash_aref(field_info, element_sym);
490
+ if (!NIL_P(element_info)) {
491
+ int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
492
+ if (specified_element_type == element_ttype) {
493
+ result = rb_ary_new2(num_elements);
494
+
495
+ for (i = 0; i < num_elements; ++i) {
496
+ rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
497
+ }
498
+ } else {
499
+ skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
500
+ }
501
+ } else {
502
+ skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
503
+ }
504
+
505
+ default_read_list_end(protocol);
506
+ } else if (ttype == TTYPE_SET) {
507
+ VALUE items;
508
+ int i;
509
+
510
+ VALUE set_header = default_read_set_begin(protocol);
511
+ int element_ttype = FIX2INT(rb_ary_entry(set_header, 0));
512
+ int num_elements = FIX2INT(rb_ary_entry(set_header, 1));
513
+
514
+ // Check the declared element type against the expected one and skip the set contents
515
+ // if the types don't match.
516
+ VALUE element_info = rb_hash_aref(field_info, element_sym);
517
+ if (!NIL_P(element_info)) {
518
+ int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
519
+ if (specified_element_type == element_ttype) {
520
+ items = rb_ary_new2(num_elements);
521
+
522
+ for (i = 0; i < num_elements; ++i) {
523
+ rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
524
+ }
525
+
526
+ result = rb_class_new_instance(1, &items, rb_cSet);
527
+ } else {
528
+ skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
529
+ }
530
+ } else {
531
+ skip_list_or_set_contents(protocol, INT2FIX(element_ttype), num_elements);
532
+ }
533
+
534
+ default_read_set_end(protocol);
535
+ } else {
536
+ rb_raise(rb_eNotImpError, "read_anything not implemented for type %d!", ttype);
537
+ }
538
+
539
+ return result;
540
+ }
541
+
542
+ static VALUE rb_thrift_struct_read(VALUE self, VALUE protocol) {
543
+ // read struct begin
544
+ default_read_struct_begin(protocol);
545
+
546
+ VALUE struct_fields = STRUCT_FIELDS(self);
547
+
548
+ // read each field
549
+ while (true) {
550
+ VALUE field_header = default_read_field_begin(protocol);
551
+ VALUE field_type_value = rb_ary_entry(field_header, 1);
552
+ int field_type = FIX2INT(field_type_value);
553
+
554
+ if (field_type == TTYPE_STOP) {
555
+ break;
556
+ }
557
+
558
+ // make sure we got a type we expected
559
+ VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
560
+
561
+ if (!NIL_P(field_info)) {
562
+ int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
563
+ if (field_type == specified_type) {
564
+ // read the value
565
+ VALUE name = rb_hash_aref(field_info, name_sym);
566
+ set_field_value(self, name, read_anything(protocol, field_type, field_info));
567
+ } else {
568
+ rb_funcall(protocol, skip_method_id, 1, field_type_value);
569
+ }
570
+ } else {
571
+ rb_funcall(protocol, skip_method_id, 1, field_type_value);
572
+ }
573
+
574
+ // read field end
575
+ default_read_field_end(protocol);
576
+ }
577
+
578
+ // read struct end
579
+ default_read_struct_end(protocol);
580
+
581
+ // call validate
582
+ rb_funcall(self, validate_method_id, 0);
583
+
584
+ return Qnil;
585
+ }
586
+
587
+
588
+ // --------------------------------
589
+ // Union section
590
+ // --------------------------------
591
+
592
+ static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) {
593
+ // read struct begin
594
+ default_read_struct_begin(protocol);
595
+
596
+ VALUE struct_fields = STRUCT_FIELDS(self);
597
+
598
+ VALUE field_header = default_read_field_begin(protocol);
599
+ VALUE field_type_value = rb_ary_entry(field_header, 1);
600
+ int field_type = FIX2INT(field_type_value);
601
+
602
+ // make sure we got a type we expected
603
+ VALUE field_info = rb_hash_aref(struct_fields, rb_ary_entry(field_header, 2));
604
+
605
+ if (!NIL_P(field_info)) {
606
+ int specified_type = FIX2INT(rb_hash_aref(field_info, type_sym));
607
+ if (field_type == specified_type) {
608
+ // read the value
609
+ VALUE name = rb_hash_aref(field_info, name_sym);
610
+ rb_iv_set(self, "@setfield", rb_str_intern(name));
611
+ rb_iv_set(self, "@value", read_anything(protocol, field_type, field_info));
612
+ } else {
613
+ rb_funcall(protocol, skip_method_id, 1, field_type_value);
614
+ }
615
+ } else {
616
+ rb_funcall(protocol, skip_method_id, 1, field_type_value);
617
+ }
618
+
619
+ // read field end
620
+ default_read_field_end(protocol);
621
+
622
+ field_header = default_read_field_begin(protocol);
623
+ field_type_value = rb_ary_entry(field_header, 1);
624
+ field_type = FIX2INT(field_type_value);
625
+
626
+ if (field_type != TTYPE_STOP) {
627
+ rb_raise(rb_eRuntimeError, "too many fields in union!");
628
+ }
629
+
630
+ // read struct end
631
+ default_read_struct_end(protocol);
632
+
633
+ // call validate
634
+ rb_funcall(self, validate_method_id, 0);
635
+
636
+ return Qnil;
637
+ }
638
+
639
+ static VALUE rb_thrift_union_write(VALUE self, VALUE protocol) {
640
+ // call validate
641
+ rb_funcall(self, validate_method_id, 0);
642
+
643
+ // write struct begin
644
+ default_write_struct_begin(protocol, rb_class_name(CLASS_OF(self)));
645
+
646
+ VALUE struct_fields = STRUCT_FIELDS(self);
647
+
648
+ VALUE setfield = rb_ivar_get(self, setfield_id);
649
+ VALUE setvalue = rb_ivar_get(self, setvalue_id);
650
+ VALUE field_id = rb_funcall(self, name_to_id_method_id, 1, rb_funcall(setfield, to_s_method_id, 0));
651
+
652
+ VALUE field_info = rb_hash_aref(struct_fields, field_id);
653
+
654
+ VALUE ttype_value = rb_hash_aref(field_info, type_sym);
655
+ int ttype = FIX2INT(ttype_value);
656
+
657
+ default_write_field_begin(protocol, setfield, ttype_value, field_id);
658
+
659
+ write_anything(ttype, setvalue, protocol, field_info);
660
+
661
+ default_write_field_end(protocol);
662
+
663
+ default_write_field_stop(protocol);
664
+
665
+ // write struct end
666
+ default_write_struct_end(protocol);
667
+
668
+ return Qnil;
669
+ }
670
+
671
+ void Init_struct() {
672
+ VALUE struct_module = rb_const_get(thrift_module, rb_intern("Struct"));
673
+
674
+ rb_define_method(struct_module, "write", rb_thrift_struct_write, 1);
675
+ rb_define_method(struct_module, "read", rb_thrift_struct_read, 1);
676
+
677
+ thrift_union_class = rb_const_get(thrift_module, rb_intern("Union"));
678
+
679
+ rb_define_method(thrift_union_class, "write", rb_thrift_union_write, 1);
680
+ rb_define_method(thrift_union_class, "read", rb_thrift_union_read, 1);
681
+
682
+ setfield_id = rb_intern("@setfield");
683
+ setvalue_id = rb_intern("@value");
684
+
685
+ to_s_method_id = rb_intern("to_s");
686
+ name_to_id_method_id = rb_intern("name_to_id");
687
+ sorted_field_ids_method_id = rb_intern("sorted_field_ids");
688
+ }