1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 2013-2015 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 "../grn_db.h"
21#include <string.h>
22
23#ifdef GRN_WITH_MRUBY
24#include <mruby.h>
25#include <mruby/class.h>
26#include <mruby/data.h>
27#include <mruby/string.h>
28
29#include "mrb_converter.h"
30#include "mrb_bulk.h"
31
32void
33grn_mrb_value_to_raw_data_buffer_init(mrb_state *mrb,
34 grn_mrb_value_to_raw_data_buffer *buffer)
35{
36 GRN_VOID_INIT(&(buffer->from));
37 GRN_VOID_INIT(&(buffer->to));
38}
39
40void
41grn_mrb_value_to_raw_data_buffer_fin(mrb_state *mrb,
42 grn_mrb_value_to_raw_data_buffer *buffer)
43{
44 grn_ctx *ctx = (grn_ctx *)mrb->ud;
45
46 GRN_OBJ_FIN(ctx, &(buffer->from));
47 GRN_OBJ_FIN(ctx, &(buffer->to));
48}
49
50void
51grn_mrb_value_to_raw_data(mrb_state *mrb,
52 const char *context,
53 mrb_value mrb_value_,
54 grn_id domain_id,
55 grn_mrb_value_to_raw_data_buffer *buffer,
56 void **raw_value,
57 unsigned int *raw_value_size)
58{
59 grn_ctx *ctx = (grn_ctx *)mrb->ud;
60 enum mrb_vtype mrb_value_type;
61 grn_bool try_cast = GRN_FALSE;
62 grn_obj *from_bulk = NULL;
63
64 if (mrb_nil_p(mrb_value_)) {
65 *raw_value = NULL;
66 *raw_value_size = 0;
67 return;
68 }
69
70 mrb_value_type = mrb_type(mrb_value_);
71
72 switch (mrb_value_type) {
73 case MRB_TT_STRING :
74 switch (domain_id) {
75 case GRN_DB_SHORT_TEXT :
76 case GRN_DB_TEXT :
77 case GRN_DB_LONG_TEXT :
78 *raw_value = RSTRING_PTR(mrb_value_);
79 *raw_value_size = RSTRING_LEN(mrb_value_);
80 break;
81 default :
82 try_cast = GRN_TRUE;
83 break;
84 }
85 break;
86 default :
87 {
88 struct RClass *klass;
89 grn_mrb_data *data = &(ctx->impl->mrb);
90
91 klass = mrb_class(mrb, mrb_value_);
92 if (domain_id == GRN_DB_TIME &&
93 klass == data->builtin.time_class) {
94 mrb_value mrb_sec;
95 mrb_value mrb_usec;
96
97 mrb_sec = mrb_funcall(mrb, mrb_value_, "to_i", 0);
98 mrb_usec = mrb_funcall(mrb, mrb_value_, "usec", 0);
99 buffer->value.time_value = GRN_TIME_PACK(mrb_fixnum(mrb_sec),
100 mrb_fixnum(mrb_usec));
101 *raw_value = &(buffer->value.time_value);
102 *raw_value_size = sizeof(buffer->value.time_value);
103 } else {
104 try_cast = GRN_TRUE;
105 if (mrb_value_type == MRB_TT_DATA &&
106 klass == mrb_class_get_under(mrb, data->module, "Bulk")) {
107 from_bulk = DATA_PTR(mrb_value_);
108 }
109 }
110 }
111 break;
112 }
113
114 if (!try_cast) {
115 return;
116 }
117
118 if (!from_bulk) {
119 from_bulk = &(buffer->from);
120 grn_mrb_value_to_bulk(mrb, mrb_value_, from_bulk);
121 }
122 if (!grn_mrb_bulk_cast(mrb, from_bulk, &(buffer->to), domain_id)) {
123 grn_obj *domain;
124 char domain_name[GRN_TABLE_MAX_KEY_SIZE];
125 int domain_name_size;
126
127 domain = grn_ctx_at(ctx, domain_id);
128 domain_name_size = grn_obj_name(ctx, domain, domain_name,
129 GRN_TABLE_MAX_KEY_SIZE);
130 mrb_raisef(mrb, E_ARGUMENT_ERROR,
131 "%S: failed to convert to %S: %S",
132 mrb_str_new_static(mrb, context, strlen(context)),
133 mrb_str_new_static(mrb, domain_name, domain_name_size),
134 mrb_funcall(mrb, mrb_value_, "inspect", 0));
135 }
136 *raw_value = GRN_BULK_HEAD(&(buffer->to));
137 *raw_value_size = GRN_BULK_VSIZE(&(buffer->to));
138}
139
140mrb_value
141grn_mrb_value_from_raw_data(mrb_state *mrb,
142 grn_id domain,
143 void *raw_value,
144 unsigned int raw_value_size)
145{
146 grn_ctx *ctx = (grn_ctx *)mrb->ud;
147 mrb_value mrb_value_;
148
149 switch (domain) {
150 case GRN_DB_INT32 :
151 if (raw_value_size == 0) {
152 mrb_value_ = mrb_fixnum_value(0);
153 } else {
154 int32_t value;
155 value = *((int32_t *)raw_value);
156 mrb_value_ = mrb_fixnum_value(value);
157 }
158 break;
159 case GRN_DB_SHORT_TEXT :
160 case GRN_DB_TEXT :
161 case GRN_DB_LONG_TEXT :
162 mrb_value_ = mrb_str_new(mrb,
163 raw_value,
164 raw_value_size);
165 break;
166 default :
167 {
168 grn_obj *domain_object;
169#define MESSAGE_SIZE 4096
170 char message[MESSAGE_SIZE];
171 char domain_name[GRN_TABLE_MAX_KEY_SIZE];
172 int domain_name_size;
173
174 domain_object = grn_ctx_at(ctx, domain);
175 if (domain_object) {
176 domain_name_size = grn_obj_name(ctx, domain_object,
177 domain_name, GRN_TABLE_MAX_KEY_SIZE);
178 grn_obj_unlink(ctx, domain_object);
179 } else {
180 grn_strcpy(domain_name, GRN_TABLE_MAX_KEY_SIZE, "unknown");
181 domain_name_size = strlen(domain_name);
182 }
183 grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
184 "unsupported raw value type: <%d>(%.*s)",
185 domain,
186 domain_name_size,
187 domain_name);
188 mrb_raise(mrb, E_RANGE_ERROR, message);
189 }
190#undef MESSAGE_SIZE
191 break;
192 }
193
194 return mrb_value_;
195}
196
197struct RClass *
198grn_mrb_class_from_grn_obj(mrb_state *mrb, grn_obj *object)
199{
200 grn_ctx *ctx = (grn_ctx *)mrb->ud;
201 grn_mrb_data *data;
202 struct RClass *klass = NULL;
203
204 data = &(ctx->impl->mrb);
205 switch (object->header.type) {
206 case GRN_BULK :
207 klass = mrb_class_get_under(mrb, data->module, "Bulk");
208 break;
209 case GRN_PTR :
210 klass = mrb_class_get_under(mrb, data->module, "Pointer");
211 break;
212 case GRN_ACCESSOR :
213 klass = mrb_class_get_under(mrb, data->module, "Accessor");
214 break;
215 case GRN_COLUMN_FIX_SIZE :
216 klass = mrb_class_get_under(mrb, data->module, "FixedSizeColumn");
217 break;
218 case GRN_COLUMN_VAR_SIZE :
219 klass = mrb_class_get_under(mrb, data->module, "VariableSizeColumn");
220 break;
221 case GRN_COLUMN_INDEX :
222 klass = mrb_class_get_under(mrb, data->module, "IndexColumn");
223 break;
224 case GRN_TYPE :
225 klass = mrb_class_get_under(mrb, data->module, "Type");
226 break;
227 case GRN_PROC :
228 klass = mrb_class_get_under(mrb, data->module, "Procedure");
229 break;
230 case GRN_EXPR :
231 klass = mrb_class_get_under(mrb, data->module, "Expression");
232 break;
233 case GRN_TABLE_NO_KEY :
234 klass = mrb_class_get_under(mrb, data->module, "Array");
235 break;
236 case GRN_TABLE_HASH_KEY :
237 klass = mrb_class_get_under(mrb, data->module, "HashTable");
238 break;
239 case GRN_TABLE_PAT_KEY :
240 klass = mrb_class_get_under(mrb, data->module, "PatriciaTrie");
241 break;
242 case GRN_TABLE_DAT_KEY :
243 klass = mrb_class_get_under(mrb, data->module, "DoubleArrayTrie");
244 break;
245 case GRN_DB :
246 klass = mrb_class_get_under(mrb, data->module, "Database");
247 break;
248 case GRN_VOID :
249 klass = mrb_class_get_under(mrb, data->module, "Void");
250 break;
251 default :
252 break;
253 }
254
255 if (!klass) {
256#define BUFFER_SIZE 1024
257 char buffer[BUFFER_SIZE];
258 grn_snprintf(buffer, BUFFER_SIZE, BUFFER_SIZE,
259 "can't find class for object type: %#x", object->header.type);
260 mrb_raise(mrb, E_ARGUMENT_ERROR, buffer);
261#undef BUFFER_SIZE
262 }
263
264 return klass;
265}
266
267mrb_value
268grn_mrb_value_from_grn_obj(mrb_state *mrb, grn_obj *object)
269{
270 struct RClass *mrb_class;
271 mrb_value mrb_new_arguments[1];
272 mrb_value mrb_object;
273
274 if (!object) {
275 return mrb_nil_value();
276 }
277
278 mrb_class = grn_mrb_class_from_grn_obj(mrb, object);
279 mrb_new_arguments[0] = mrb_cptr_value(mrb, object);
280 mrb_object = mrb_obj_new(mrb, mrb_class, 1, mrb_new_arguments);
281 return mrb_object;
282}
283
284grn_id
285grn_mrb_class_to_type(mrb_state *mrb, struct RClass *klass)
286{
287 grn_ctx *ctx = (grn_ctx *)mrb->ud;
288 grn_id type = GRN_DB_VOID;
289
290 if (klass == mrb->nil_class) {
291 type = GRN_DB_VOID;
292 } else if (klass == mrb->true_class ||
293 klass == mrb->false_class) {
294 type = GRN_DB_BOOL;
295 } else if (klass == mrb->symbol_class) {
296 type = GRN_DB_TEXT;
297 } else if (klass == mrb->fixnum_class) {
298 type = GRN_DB_INT64;
299 } else if (klass == mrb->float_class) {
300 type = GRN_DB_FLOAT;
301 } else if (klass == mrb->string_class) {
302 type = GRN_DB_TEXT;
303 } else if (klass == ctx->impl->mrb.builtin.time_class) {
304 type = GRN_DB_TIME;
305 } else {
306 mrb_raisef(mrb, E_ARGUMENT_ERROR,
307 "unsupported class: %S", mrb_obj_value(klass));
308 }
309
310 return type;
311}
312
313static mrb_value
314mrb_grn_converter_class_convert(mrb_state *mrb, mrb_value klass)
315{
316 grn_ctx *ctx = (grn_ctx *)mrb->ud;
317 grn_obj *from = &(ctx->impl->mrb.buffer.from);
318 grn_obj *to = &(ctx->impl->mrb.buffer.to);
319 mrb_value mrb_from;
320 mrb_value mrb_to_class;
321 grn_id to_type;
322
323 mrb_get_args(mrb, "oC", &mrb_from, &mrb_to_class);
324
325 grn_mrb_value_to_bulk(mrb, mrb_from, from);
326 to_type = grn_mrb_class_to_type(mrb, mrb_class_ptr(mrb_to_class));
327 if (!grn_mrb_bulk_cast(mrb, from, to, to_type)) {
328 mrb_raisef(mrb, E_ARGUMENT_ERROR,
329 "failed to convert to %S: %S",
330 mrb_to_class,
331 mrb_from);
332 }
333
334 return grn_mrb_value_from_bulk(mrb, to);
335}
336
337void
338grn_mrb_converter_init(grn_ctx *ctx)
339{
340 grn_mrb_data *data = &(ctx->impl->mrb);
341 mrb_state *mrb = data->state;
342 struct RClass *module;
343
344 module = mrb_define_module_under(mrb, data->module, "Converter");
345
346 mrb_define_class_method(mrb, module, "convert",
347 mrb_grn_converter_class_convert,
348 MRB_ARGS_REQ(2));
349}
350#endif
351