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
34static struct mrb_data_type mrb_grn_bulk_type = {
35 "Groonga::Bulk",
36 NULL
37};
38
39grn_obj *
40grn_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
106mrb_value
107grn_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
279grn_bool
280grn_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
290static mrb_value
291mrb_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
308static mrb_value
309mrb_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
319static mrb_value
320mrb_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
328static mrb_value
329mrb_grn_bulk_get_value(mrb_state *mrb, mrb_value self)
330{
331 return grn_mrb_value_from_bulk(mrb, DATA_PTR(self));
332}
333
334static mrb_value
335mrb_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
348void
349grn_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