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-1335  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 
32 void
grn_mrb_value_to_raw_data_buffer_init(mrb_state * mrb,grn_mrb_value_to_raw_data_buffer * buffer)33 grn_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 
40 void
grn_mrb_value_to_raw_data_buffer_fin(mrb_state * mrb,grn_mrb_value_to_raw_data_buffer * buffer)41 grn_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 
50 void
grn_mrb_value_to_raw_data(mrb_state * mrb,const char * context,mrb_value mrb_value_,grn_id domain_id,grn_mrb_value_to_raw_data_buffer * buffer,void ** raw_value,unsigned int * raw_value_size)51 grn_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 
140 mrb_value
grn_mrb_value_from_raw_data(mrb_state * mrb,grn_id domain,void * raw_value,unsigned int raw_value_size)141 grn_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 
197 struct RClass *
grn_mrb_class_from_grn_obj(mrb_state * mrb,grn_obj * object)198 grn_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 
267 mrb_value
grn_mrb_value_from_grn_obj(mrb_state * mrb,grn_obj * object)268 grn_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 
284 grn_id
grn_mrb_class_to_type(mrb_state * mrb,struct RClass * klass)285 grn_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 
313 static mrb_value
mrb_grn_converter_class_convert(mrb_state * mrb,mrb_value klass)314 mrb_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 
337 void
grn_mrb_converter_init(grn_ctx * ctx)338 grn_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