1 | /* -*- c-basic-offset: 2 -*- */ |
2 | /* |
3 | Copyright(C) 2014-2016 Brazil |
4 | |
5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License version 2.1 as published by the Free Software Foundation. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with this library; if not, write to the Free Software |
16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ |
18 | |
19 | #include "../grn_ctx_impl.h" |
20 | #include <string.h> |
21 | |
22 | #ifdef GRN_WITH_MRUBY |
23 | #include <mruby.h> |
24 | #include <mruby/class.h> |
25 | #include <mruby/variable.h> |
26 | #include <mruby/data.h> |
27 | #include <mruby/numeric.h> |
28 | #include <mruby/string.h> |
29 | |
30 | #include "../grn_db.h" |
31 | #include "mrb_bulk.h" |
32 | #include "mrb_object.h" |
33 | |
34 | static struct mrb_data_type mrb_grn_bulk_type = { |
35 | "Groonga::Bulk" , |
36 | NULL |
37 | }; |
38 | |
39 | grn_obj * |
40 | grn_mrb_value_to_bulk(mrb_state *mrb, mrb_value mrb_value_, grn_obj *bulk) |
41 | { |
42 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
43 | |
44 | switch (mrb_type(mrb_value_)) { |
45 | case MRB_TT_FALSE : |
46 | if (mrb_nil_p(mrb_value_)) { |
47 | grn_obj_reinit(ctx, bulk, GRN_DB_VOID, 0); |
48 | } else { |
49 | grn_obj_reinit(ctx, bulk, GRN_DB_BOOL, 0); |
50 | GRN_BOOL_SET(ctx, bulk, GRN_FALSE); |
51 | } |
52 | break; |
53 | case MRB_TT_TRUE : |
54 | grn_obj_reinit(ctx, bulk, GRN_DB_BOOL, 0); |
55 | GRN_BOOL_SET(ctx, bulk, GRN_TRUE); |
56 | break; |
57 | case MRB_TT_FIXNUM : |
58 | grn_obj_reinit(ctx, bulk, GRN_DB_INT64, 0); |
59 | GRN_INT64_SET(ctx, bulk, mrb_fixnum(mrb_value_)); |
60 | break; |
61 | case MRB_TT_SYMBOL : |
62 | { |
63 | const char *name; |
64 | mrb_int name_length; |
65 | |
66 | grn_obj_reinit(ctx, bulk, GRN_DB_TEXT, 0); |
67 | name = mrb_sym2name_len(mrb, mrb_symbol(mrb_value_), &name_length); |
68 | GRN_TEXT_SET(ctx, bulk, name, name_length); |
69 | } |
70 | break; |
71 | case MRB_TT_FLOAT : |
72 | grn_obj_reinit(ctx, bulk, GRN_DB_FLOAT, 0); |
73 | GRN_FLOAT_SET(ctx, bulk, mrb_float(mrb_value_)); |
74 | break; |
75 | case MRB_TT_STRING : |
76 | grn_obj_reinit(ctx, bulk, GRN_DB_TEXT, |
77 | bulk->header.impl_flags & GRN_OBJ_DO_SHALLOW_COPY); |
78 | GRN_TEXT_SET(ctx, bulk, RSTRING_PTR(mrb_value_), RSTRING_LEN(mrb_value_)); |
79 | break; |
80 | default : |
81 | { |
82 | struct RClass *klass; |
83 | |
84 | klass = mrb_class(mrb, mrb_value_); |
85 | if (klass == ctx->impl->mrb.builtin.time_class) { |
86 | mrb_value mrb_sec; |
87 | mrb_value mrb_usec; |
88 | |
89 | mrb_sec = mrb_funcall(mrb, mrb_value_, "to_i" , 0); |
90 | mrb_usec = mrb_funcall(mrb, mrb_value_, "usec" , 0); |
91 | grn_obj_reinit(ctx, bulk, GRN_DB_TIME, 0); |
92 | GRN_TIME_SET(ctx, bulk, |
93 | GRN_TIME_PACK(mrb_fixnum(mrb_sec), mrb_fixnum(mrb_usec))); |
94 | } else { |
95 | mrb_raisef(mrb, E_ARGUMENT_ERROR, |
96 | "unsupported object to convert to bulk: %S" , |
97 | mrb_value_); |
98 | } |
99 | } |
100 | break; |
101 | } |
102 | |
103 | return bulk; |
104 | } |
105 | |
106 | mrb_value |
107 | grn_mrb_value_from_bulk(mrb_state *mrb, grn_obj *bulk) |
108 | { |
109 | mrb_value mrb_value_; |
110 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
111 | |
112 | if (!bulk) { |
113 | return mrb_nil_value(); |
114 | } |
115 | |
116 | switch (bulk->header.domain) { |
117 | case GRN_DB_BOOL : |
118 | { |
119 | grn_bool value; |
120 | value = GRN_BOOL_VALUE(bulk); |
121 | mrb_value_ = mrb_bool_value(value); |
122 | } |
123 | break; |
124 | case GRN_DB_INT8 : |
125 | { |
126 | int8_t value; |
127 | value = GRN_INT8_VALUE(bulk); |
128 | mrb_value_ = mrb_fixnum_value(value); |
129 | } |
130 | break; |
131 | case GRN_DB_UINT8 : |
132 | { |
133 | uint8_t value; |
134 | value = GRN_UINT8_VALUE(bulk); |
135 | mrb_value_ = mrb_fixnum_value(value); |
136 | } |
137 | break; |
138 | case GRN_DB_INT16 : |
139 | { |
140 | int16_t value; |
141 | value = GRN_INT16_VALUE(bulk); |
142 | mrb_value_ = mrb_fixnum_value(value); |
143 | } |
144 | break; |
145 | case GRN_DB_UINT16 : |
146 | { |
147 | uint16_t value; |
148 | value = GRN_UINT16_VALUE(bulk); |
149 | mrb_value_ = mrb_fixnum_value(value); |
150 | } |
151 | break; |
152 | case GRN_DB_INT32 : |
153 | { |
154 | int32_t value; |
155 | value = GRN_INT32_VALUE(bulk); |
156 | mrb_value_ = mrb_fixnum_value(value); |
157 | } |
158 | break; |
159 | case GRN_DB_UINT32 : |
160 | { |
161 | int64_t value; |
162 | value = GRN_UINT32_VALUE(bulk); |
163 | if (FIXABLE(value)) { |
164 | mrb_value_ = mrb_fixnum_value(value); |
165 | } else { |
166 | mrb_value_ = mrb_float_value(mrb, value); |
167 | } |
168 | } |
169 | break; |
170 | case GRN_DB_INT64 : |
171 | { |
172 | int64_t value; |
173 | value = GRN_INT64_VALUE(bulk); |
174 | if (FIXABLE(value)) { |
175 | mrb_value_ = mrb_fixnum_value(value); |
176 | } else { |
177 | mrb_value_ = mrb_float_value(mrb, value); |
178 | } |
179 | } |
180 | break; |
181 | case GRN_DB_UINT64 : |
182 | { |
183 | uint64_t value; |
184 | value = GRN_UINT64_VALUE(bulk); |
185 | if (FIXABLE(value)) { |
186 | mrb_value_ = mrb_fixnum_value(value); |
187 | } else { |
188 | mrb_value_ = mrb_float_value(mrb, value); |
189 | } |
190 | } |
191 | break; |
192 | case GRN_DB_FLOAT : |
193 | { |
194 | double value; |
195 | value = GRN_FLOAT_VALUE(bulk); |
196 | mrb_value_ = mrb_float_value(mrb, value); |
197 | } |
198 | break; |
199 | case GRN_DB_TIME : |
200 | { |
201 | int64_t value; |
202 | int64_t sec; |
203 | int32_t usec; |
204 | mrb_value mrb_sec; |
205 | |
206 | value = GRN_TIME_VALUE(bulk); |
207 | GRN_TIME_UNPACK(value, sec, usec); |
208 | if (sec > MRB_INT_MAX) { |
209 | mrb_sec = mrb_float_value(mrb, sec); |
210 | } else { |
211 | mrb_sec = mrb_fixnum_value(sec); |
212 | } |
213 | mrb_value_ = mrb_funcall(mrb, |
214 | mrb_obj_value(ctx->impl->mrb.builtin.time_class), |
215 | "at" , |
216 | 2, |
217 | mrb_sec, |
218 | mrb_fixnum_value(usec)); |
219 | } |
220 | break; |
221 | case GRN_DB_SHORT_TEXT : |
222 | case GRN_DB_TEXT : |
223 | case GRN_DB_LONG_TEXT : |
224 | mrb_value_ = mrb_str_new(mrb, |
225 | GRN_TEXT_VALUE(bulk), |
226 | GRN_TEXT_LEN(bulk)); |
227 | break; |
228 | default : |
229 | { |
230 | grn_obj *domain; |
231 | grn_bool is_record = GRN_FALSE; |
232 | |
233 | domain = grn_ctx_at(ctx, bulk->header.domain); |
234 | if (domain) { |
235 | switch (domain->header.type) { |
236 | case GRN_TABLE_HASH_KEY : |
237 | case GRN_TABLE_PAT_KEY : |
238 | case GRN_TABLE_DAT_KEY : |
239 | case GRN_TABLE_NO_KEY : |
240 | is_record = GRN_TRUE; |
241 | break; |
242 | default : |
243 | break; |
244 | } |
245 | } |
246 | |
247 | if (is_record) { |
248 | mrb_value_ = mrb_fixnum_value(GRN_RECORD_VALUE(bulk)); |
249 | grn_obj_unlink(ctx, domain); |
250 | } else { |
251 | #define MESSAGE_SIZE 4096 |
252 | char message[MESSAGE_SIZE]; |
253 | char domain_name[GRN_TABLE_MAX_KEY_SIZE]; |
254 | int domain_name_size; |
255 | |
256 | if (domain) { |
257 | domain_name_size = grn_obj_name(ctx, domain, |
258 | domain_name, GRN_TABLE_MAX_KEY_SIZE); |
259 | grn_obj_unlink(ctx, domain); |
260 | } else { |
261 | grn_strcpy(domain_name, GRN_TABLE_MAX_KEY_SIZE, "unknown" ); |
262 | domain_name_size = strlen(domain_name); |
263 | } |
264 | grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE, |
265 | "unsupported bulk value type: <%d>(%.*s)" , |
266 | bulk->header.domain, |
267 | domain_name_size, |
268 | domain_name); |
269 | mrb_raise(mrb, E_RANGE_ERROR, message); |
270 | } |
271 | #undef MESSAGE_SIZE |
272 | } |
273 | break; |
274 | } |
275 | |
276 | return mrb_value_; |
277 | } |
278 | |
279 | grn_bool |
280 | grn_mrb_bulk_cast(mrb_state *mrb, grn_obj *from, grn_obj *to, grn_id domain_id) |
281 | { |
282 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
283 | grn_rc rc; |
284 | |
285 | grn_obj_reinit(ctx, to, domain_id, 0); |
286 | rc = grn_obj_cast(ctx, from, to, GRN_FALSE); |
287 | return rc == GRN_SUCCESS; |
288 | } |
289 | |
290 | static mrb_value |
291 | mrb_grn_bulk_s_is_true(mrb_state *mrb, mrb_value klass) |
292 | { |
293 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
294 | mrb_value mrb_value_; |
295 | grn_obj bulk; |
296 | grn_bool is_true; |
297 | |
298 | mrb_get_args(mrb, "o" , &mrb_value_); |
299 | |
300 | GRN_TEXT_INIT(&bulk, GRN_OBJ_DO_SHALLOW_COPY); |
301 | grn_mrb_value_to_bulk(mrb, mrb_value_, &bulk); |
302 | is_true = grn_obj_is_true(ctx, &bulk); |
303 | GRN_OBJ_FIN(ctx, &bulk); |
304 | |
305 | return mrb_bool_value(is_true); |
306 | } |
307 | |
308 | static mrb_value |
309 | mrb_grn_bulk_initialize(mrb_state *mrb, mrb_value self) |
310 | { |
311 | mrb_value mrb_bulk_ptr; |
312 | |
313 | mrb_get_args(mrb, "o" , &mrb_bulk_ptr); |
314 | DATA_TYPE(self) = &mrb_grn_bulk_type; |
315 | DATA_PTR(self) = mrb_cptr(mrb_bulk_ptr); |
316 | return self; |
317 | } |
318 | |
319 | static mrb_value |
320 | mrb_grn_bulk_get_domain(mrb_state *mrb, mrb_value self) |
321 | { |
322 | grn_obj *bulk; |
323 | |
324 | bulk = DATA_PTR(self); |
325 | return mrb_fixnum_value(bulk->header.domain); |
326 | } |
327 | |
328 | static mrb_value |
329 | mrb_grn_bulk_get_value(mrb_state *mrb, mrb_value self) |
330 | { |
331 | return grn_mrb_value_from_bulk(mrb, DATA_PTR(self)); |
332 | } |
333 | |
334 | static mrb_value |
335 | mrb_grn_bulk_equal(mrb_state *mrb, mrb_value self) |
336 | { |
337 | mrb_value mrb_other; |
338 | |
339 | mrb_get_args(mrb, "o" , &mrb_other); |
340 | |
341 | if (!mrb_obj_is_kind_of(mrb, mrb_other, mrb_class(mrb, self))) { |
342 | return mrb_false_value(); |
343 | } |
344 | |
345 | return mrb_bool_value(DATA_PTR(self) == DATA_PTR(mrb_other)); |
346 | } |
347 | |
348 | void |
349 | grn_mrb_bulk_init(grn_ctx *ctx) |
350 | { |
351 | grn_mrb_data *data = &(ctx->impl->mrb); |
352 | mrb_state *mrb = data->state; |
353 | struct RClass *module = data->module; |
354 | struct RClass *klass; |
355 | |
356 | klass = mrb_define_class_under(mrb, module, "Bulk" , mrb->object_class); |
357 | MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA); |
358 | |
359 | mrb_define_singleton_method(mrb, (struct RObject *)klass, "true?" , |
360 | mrb_grn_bulk_s_is_true, MRB_ARGS_REQ(1)); |
361 | |
362 | mrb_define_method(mrb, klass, "initialize" , |
363 | mrb_grn_bulk_initialize, MRB_ARGS_REQ(1)); |
364 | mrb_define_method(mrb, klass, "domain" , |
365 | mrb_grn_bulk_get_domain, MRB_ARGS_NONE()); |
366 | mrb_define_method(mrb, klass, "value" , |
367 | mrb_grn_bulk_get_value, MRB_ARGS_NONE()); |
368 | mrb_define_method(mrb, klass, "==" , |
369 | mrb_grn_bulk_equal, MRB_ARGS_REQ(1)); |
370 | mrb_define_method(mrb, klass, "inspect" , |
371 | grn_mrb_object_inspect, MRB_ARGS_NONE()); |
372 | } |
373 | #endif |
374 | |