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
rb_thrift_memory_buffer_write(VALUE self,VALUE str)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
rb_thrift_memory_buffer_read(VALUE self,VALUE length_value)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
rb_thrift_memory_buffer_read_byte(VALUE self)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
rb_thrift_memory_buffer_read_into_buffer(VALUE self,VALUE buffer_value,VALUE size_value)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
Init_memory_buffer()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 }
135