00001 #include "typelib.hh"
00002 #include <iostream>
00003
00004 #include <boost/bind.hpp>
00005 #include <typelib/value_ops.hh>
00006
00007 using namespace Typelib;
00008 using std::vector;
00009 using namespace typelib_ruby;
00010
00011
00012
00013
00014
00015 static VALUE compound_get_fields(VALUE self)
00016 {
00017 if (self == cCompound)
00018 return rb_ary_new();
00019
00020 Type const& type(rb2cxx::object<Type>(self));
00021 Compound const& compound(dynamic_cast<Compound const&>(type));
00022 Compound::FieldList const& fields(compound.getFields());
00023 Compound::FieldList::const_iterator it, end = fields.end();
00024
00025 VALUE registry = type_get_registry(self);
00026 VALUE fieldlist = rb_ary_new();
00027 for (it = fields.begin(); it != end; ++it)
00028 {
00029 VALUE field_name = rb_str_new2(it->getName().c_str());
00030 VALUE field_type = cxx2rb::type_wrap(it->getType(), registry);
00031
00032 VALUE field_def = rb_ary_new2(3);
00033 rb_ary_store(field_def, 0, field_name);
00034 rb_ary_store(field_def, 1, INT2FIX(it->getOffset()));
00035 rb_ary_store(field_def, 2, field_type);
00036 rb_ary_push(fieldlist, field_def);
00037 }
00038
00039 return fieldlist;
00040 }
00041
00042
00043 static VALUE compound_field_get(VALUE rbvalue, VALUE name)
00044 {
00045 VALUE registry = value_get_registry(rbvalue);
00046 Value value = rb2cxx::object<Value>(rbvalue);
00047 if (! value.getData())
00048 return Qnil;
00049
00050 try {
00051 Value field_value = value_get_field(value, StringValuePtr(name));
00052 return typelib_to_ruby(field_value, registry, rbvalue);
00053 }
00054 catch(FieldNotFound)
00055 { rb_raise(rb_eArgError, "no field '%s'", StringValuePtr(name)); }
00056 catch(std::exception const& e)
00057 { rb_raise(rb_eRuntimeError, "%s", e.what()); }
00058 }
00059
00060 static VALUE compound_field_set(VALUE self, VALUE name, VALUE newval)
00061 {
00062 Value& tlib_value(rb2cxx::object<Value>(self));
00063
00064 try {
00065 Value field_value = value_get_field(tlib_value, StringValuePtr(name));
00066 typelib_from_ruby(field_value, newval);
00067 return newval;
00068 }
00069 catch(FieldNotFound)
00070 { rb_raise(rb_eArgError, "no field '%s' in '%s'", StringValuePtr(name), rb_obj_classname(self)); }
00071 catch(std::exception const& e)
00072 { rb_raise(rb_eRuntimeError, "%s", e.what()); }
00073 }
00074
00075
00076
00077
00078
00079
00080 static VALUE pointer_deference(VALUE self)
00081 {
00082 VALUE pointed_to = rb_iv_get(self, "@points_to");
00083 if (!NIL_P(pointed_to))
00084 return pointed_to;
00085
00086 Value const& value(rb2cxx::object<Value>(self));
00087 Indirect const& indirect(static_cast<Indirect const&>(value.getType()));
00088
00089 VALUE registry = value_get_registry(self);
00090
00091 void* ptr_value = *reinterpret_cast<void**>(value.getData());
00092 if (!ptr_value)
00093 rb_raise(rb_eArgError, "cannot deference a NULL pointer");
00094
00095 Value new_value(ptr_value, indirect.getIndirection() );
00096 return typelib_to_ruby(new_value, registry, Qnil);
00097 }
00098
00099
00100
00101
00102
00103 Enum::integral_type rb2cxx::enum_value(VALUE rb_value, Enum const& e)
00104 {
00105
00106 if (TYPE(rb_value) == T_FIXNUM)
00107 {
00108 Enum::integral_type value = FIX2INT(rb_value);
00109 try {
00110 e.get(value);
00111 return value;
00112 }
00113 catch(Enum::ValueNotFound) { }
00114 rb_raise(rb_eArgError, "%i is not a valid value for %s", value, e.getName().c_str());
00115 }
00116
00117 char const* name;
00118 if (SYMBOL_P(rb_value))
00119 name = rb_id2name(SYM2ID(rb_value));
00120 else
00121 name = StringValuePtr(rb_value);
00122
00123 try { return e.get(name); }
00124 catch(Enum::SymbolNotFound) { }
00125 rb_raise(rb_eArgError, "%s is not a valid symbol for %s", name, e.getName().c_str());
00126 }
00127
00128
00129
00130
00131
00132
00133 VALUE enum_keys(VALUE self)
00134 {
00135 Enum const& type = static_cast<Enum const&>(rb2cxx::object<Type>(self));
00136
00137 VALUE keys = rb_iv_get(self, "@values");
00138 if (!NIL_P(keys))
00139 return keys;
00140
00141 keys = rb_hash_new();
00142 typedef std::list<std::string> string_list;
00143 string_list names = type.names();
00144 for (string_list::const_iterator it = names.begin(); it != names.end(); ++it)
00145 rb_hash_aset(keys, rb_str_new2(it->c_str()), INT2FIX(type.get(*it)));
00146
00147 rb_iv_set(self, "@values", keys);
00148 return keys;
00149 }
00150
00151
00152
00153
00154
00155
00156 static VALUE enum_value_of(VALUE self, VALUE name)
00157 {
00158 Enum const& type = static_cast<Enum const&>(rb2cxx::object<Type>(self));
00159
00160 try {
00161 int value = type.get(StringValuePtr(name));
00162 return INT2NUM(value);
00163 } catch (Enum::SymbolNotFound) {
00164 rb_raise(rb_eArgError, "this enumeration has no value for %s", StringValuePtr(name));
00165 }
00166 }
00167
00168
00169
00170
00171
00172
00173
00174 static VALUE enum_name_of(VALUE self, VALUE integer)
00175 {
00176 Enum const& type = static_cast<Enum const&>(rb2cxx::object<Type>(self));
00177
00178 try {
00179 std::string name = type.get(NUM2INT(integer));
00180 return rb_str_new2(name.c_str());
00181 } catch (Enum::ValueNotFound) {
00182 rb_raise(rb_eArgError, "this enumeration has no name for %i", NUM2INT(integer));
00183 }
00184 }
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 static VALUE indirect_type_deference(VALUE self)
00196 {
00197 VALUE registry = type_get_registry(self);
00198 Type const& type(rb2cxx::object<Type>(self));
00199 Indirect const& indirect(static_cast<Indirect const&>(type));
00200 return cxx2rb::type_wrap(indirect.getIndirection(), registry);
00201 }
00202
00203
00204 static Value array_element(VALUE rbarray, VALUE rbindex)
00205 {
00206 Value& value(rb2cxx::object<Value>(rbarray));
00207 Array const& array(static_cast<Array const&>(value.getType()));
00208 size_t index = NUM2INT(rbindex);
00209
00210 if (index >= array.getDimension())
00211 {
00212 rb_raise(rb_eIndexError, "Out of bounds: %lu > %lu", index, array.getDimension());
00213 return Value();
00214 }
00215
00216 Type const& array_type(array.getIndirection());
00217
00218 int8_t* data = reinterpret_cast<int8_t*>(value.getData());
00219 data += array_type.getSize() * index;
00220 return Value(data, array_type);
00221 }
00222
00223
00224
00225
00226
00227
00228
00229
00230 static VALUE array_get(int argc, VALUE* argv, VALUE self)
00231 {
00232 Value& value = rb2cxx::object<Value>(self);
00233 Array const& array = static_cast<Array const&>(value.getType());
00234 if (array.getDimension() == 0)
00235 return self;
00236
00237 Type const& array_type = array.getIndirection();
00238 VALUE registry = value_get_registry(self);
00239
00240 int8_t* data = reinterpret_cast<int8_t*>(value.getData());
00241 size_t index = NUM2INT(argv[0]);
00242 if (index >= array.getDimension())
00243 rb_raise(rb_eIndexError, "Out of bounds: %li > %li", index, array.getDimension());
00244
00245 if (argc == 1)
00246 {
00247 Value v = Value(data + array_type.getSize() * index, array_type);
00248 return typelib_to_ruby( v, registry, self );
00249 }
00250 else if (argc == 2)
00251 {
00252 VALUE ret = rb_ary_new();
00253 size_t size = NUM2INT(argv[1]);
00254 if (index + size > array.getDimension())
00255 rb_raise(rb_eIndexError, "Out of bounds: %li > %li", index + size - 1, array.getDimension());
00256
00257 for (size_t i = index; i < index + size; ++i)
00258 {
00259 Value v = Value(data + array_type.getSize() * i, array_type);
00260 VALUE rb_v = typelib_to_ruby( v, registry, self );
00261
00262 rb_ary_push(ret, rb_v);
00263 }
00264
00265 return ret;
00266 }
00267 else
00268 rb_raise(rb_eArgError, "invalid argument count (%i for 1 or 2)", argc);
00269 }
00270
00271
00272
00273
00274
00275
00276
00277
00278 static VALUE array_set(VALUE self, VALUE rbindex, VALUE newvalue)
00279 {
00280 Value element = array_element(self, rbindex);
00281 return typelib_from_ruby(element, newvalue);
00282 }
00283
00284
00285
00286
00287
00288
00289 static VALUE array_do_each(VALUE rbarray)
00290 {
00291 Value& value = rb2cxx::object<Value>(rbarray);
00292 Array const& array = static_cast<Array const&>(value.getType());
00293 if (array.getDimension() == 0)
00294 return rbarray;
00295
00296 Type const& array_type = array.getIndirection();
00297 VALUE registry = value_get_registry(rbarray);
00298
00299 int8_t* data = reinterpret_cast<int8_t*>(value.getData());
00300
00301 for (size_t i = 0; i < array.getDimension(); ++i, data += array_type.getSize())
00302 rb_yield(typelib_to_ruby( Value(data, array_type), registry, rbarray ));
00303
00304 return rbarray;
00305 }
00306
00307
00308
00309
00310
00311
00312 static VALUE array_size(VALUE rbarray)
00313 {
00314 Value& value(rb2cxx::object<Value>(rbarray));
00315 Array const& array(static_cast<Array const&>(value.getType()));
00316 return INT2FIX(array.getDimension());
00317 }
00318
00319
00320
00321
00322
00323
00324 static VALUE array_class_length(VALUE rbarray)
00325 {
00326 Array const& array(dynamic_cast<Array const&>(rb2cxx::object<Type>(rbarray)));
00327 return INT2FIX(array.getDimension());
00328 }
00329
00330
00331
00332
00333
00334
00335
00336 static VALUE pointer_nil_p(VALUE self)
00337 {
00338 Value const& value(rb2cxx::object<Value>(self));
00339 if ( *reinterpret_cast<void**>(value.getData()) == 0 )
00340 return Qtrue;
00341 return Qfalse;
00342 }
00343
00344
00345
00346
00347
00348
00349
00350 static VALUE numeric_type_integer_p(VALUE self)
00351 {
00352 Numeric const& type(dynamic_cast<Numeric const&>(rb2cxx::object<Type>(self)));
00353 return type.getNumericCategory() == Numeric::Float ? Qfalse : Qtrue;
00354 }
00355
00356
00357
00358
00359
00360
00361
00362 static VALUE numeric_type_size(VALUE self)
00363 {
00364 Numeric const& type(dynamic_cast<Numeric const&>(rb2cxx::object<Type>(self)));
00365 return INT2FIX(type.getSize());
00366 }
00367
00368
00369
00370
00371
00372
00373
00374
00375 static VALUE numeric_type_unsigned_p(VALUE self)
00376 {
00377 Numeric const& type(dynamic_cast<Numeric const&>(rb2cxx::object<Type>(self)));
00378 switch(type.getNumericCategory())
00379 {
00380 case Numeric::SInt: return Qfalse;
00381 case Numeric::UInt: return Qtrue;
00382 case Numeric::Float:
00383 rb_raise(rb_eArgError, "not an integral type");
00384 }
00385 return Qnil;
00386 }
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 static VALUE container_kind(VALUE self)
00397 {
00398 Container const& type(dynamic_cast<Container const&>(rb2cxx::object<Type>(self)));
00399 return rb_str_new2(type.kind().c_str());
00400 }
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410 static VALUE container_natural_size(VALUE self)
00411 {
00412 Container const& type(dynamic_cast<Container const&>(rb2cxx::object<Type>(self)));
00413 return INT2FIX(type.getNaturalSize());
00414 }
00415
00416
00417
00418
00419
00420
00421
00422 static VALUE container_random_access_p(VALUE self)
00423 {
00424 Container const& type(dynamic_cast<Container const&>(rb2cxx::object<Type>(self)));
00425 return type.isRandomAccess() ? Qtrue : Qfalse;
00426 }
00427
00428
00429
00430
00431
00432
00433
00434
00435 static VALUE container_length(VALUE self)
00436 {
00437 Value value = rb2cxx::object<Value>(self);
00438 Container const& type(dynamic_cast<Container const&>(value.getType()));
00439
00440 return INT2NUM(type.getElementCount(value.getData()));
00441 }
00442
00443
00444
00445
00446
00447
00448
00449 static VALUE container_clear(VALUE self)
00450 {
00451 Value value = rb2cxx::object<Value>(self);
00452 Container const& type(dynamic_cast<Container const&>(value.getType()));
00453
00454 type.clear(value.getData());
00455 return Qnil;
00456 }
00457
00458 static Typelib::Value container_element(uint64_t* buffer10, Type const& element_t, VALUE obj)
00459 {
00460 Typelib::Value element_v;
00461 if (element_t.getCategory() == Type::Numeric && sizeof(int64_t) * 10 >= element_t.getSize())
00462 {
00463
00464
00465 element_v = Value(buffer10, element_t);
00466 typelib_from_ruby(element_v, obj);
00467 }
00468 else
00469 {
00470 element_v = rb2cxx::object<Value>(obj);
00471 if (element_t != element_v.getType())
00472 rb_raise(rb_eArgError, "wrong type %s for new element, expected %s", element_v.getType().getName().c_str(), element_t.getName().c_str());
00473 }
00474 return element_v;
00475 }
00476
00477 static VALUE container_do_push(VALUE self, VALUE obj)
00478 {
00479 Value container_v = rb2cxx::object<Value>(self);
00480 Container const& container_t(dynamic_cast<Container const&>(container_v.getType()));
00481
00482 uint64_t buffer[10];
00483 Value element_v = container_element(buffer, container_t.getIndirection(), obj);
00484 container_t.push(container_v.getData(), element_v);
00485 return self;
00486 }
00487
00488 static VALUE container_do_set(VALUE self, VALUE index, VALUE obj)
00489 {
00490 Value container_v = rb2cxx::object<Value>(self);
00491 Container const& container_t(dynamic_cast<Container const&>(container_v.getType()));
00492
00493 uint64_t buffer[10];
00494 Value element_v = container_element(buffer, container_t.getIndirection(), obj);
00495 container_t.setElement(container_v.getData(), NUM2INT(index), element_v);
00496 return self;
00497 }
00498
00499 static VALUE container_do_get(VALUE self, VALUE index)
00500 {
00501 Value container_v = rb2cxx::object<Value>(self);
00502 Container const& container_t(dynamic_cast<Container const&>(container_v.getType()));
00503 VALUE registry = value_get_registry(self);
00504
00505 Value v = container_t.getElement(container_v.getData(), NUM2INT(index));
00506 return typelib_to_ruby(v, registry, self);
00507 }
00508
00509 struct ContainerIterator : public RubyGetter
00510 {
00511 bool inside;
00512
00513 bool visit_(Value const& v, Container const& c)
00514 {
00515 if (inside)
00516 RubyGetter::visit_(v, c);
00517 else
00518 ValueVisitor::visit_(v, c);
00519 return false;
00520 }
00521
00522 void apply(Value v, VALUE registry, VALUE parent)
00523 {
00524 inside = false;
00525 RubyGetter::apply(v, registry, parent);
00526 }
00527 virtual void dispatch(Value v)
00528 {
00529 inside = true;
00530 RubyGetter::dispatch(v);
00531
00532 VALUE result = m_value;
00533 m_value = Qnil;
00534 rb_yield(result);
00535 }
00536 };
00537
00538
00539
00540
00541
00542
00543
00544 static VALUE container_each(VALUE self)
00545 {
00546 Value value = rb2cxx::object<Value>(self);
00547 VALUE registry = value_get_registry(self);
00548 ContainerIterator iterator;
00549 iterator.apply(value, registry, self);
00550 return self;
00551 }
00552
00553
00554
00555
00556
00557
00558
00559
00560 static VALUE container_erase(VALUE self, VALUE obj)
00561 {
00562 Value container_v = rb2cxx::object<Value>(self);
00563 Container const& container_t(dynamic_cast<Container const&>(container_v.getType()));
00564
00565 uint64_t buffer[10];
00566 Value element_v = container_element(buffer, container_t.getIndirection(), obj);
00567
00568 if (container_t.erase(container_v.getData(), element_v))
00569 return Qtrue;
00570 else
00571 return Qfalse;
00572 }
00573
00574 bool container_delete_if_i(Value v, VALUE registry, VALUE container)
00575 {
00576 VALUE rb_v = typelib_to_ruby(v, registry, container);
00577 if (RTEST(rb_yield(rb_v)))
00578 return true;
00579 return false;
00580 }
00581
00582
00583
00584
00585
00586
00587
00588 static VALUE container_delete_if(VALUE self)
00589 {
00590 Value container_v = rb2cxx::object<Value>(self);
00591 Container const& container_t(dynamic_cast<Container const&>(container_v.getType()));
00592
00593 VALUE registry = value_get_registry(self);
00594 container_t.delete_if(container_v.getData(), boost::bind(container_delete_if_i, _1, registry, self));
00595 return self;
00596 }
00597
00598
00599
00600
00601
00602
00603
00604
00605 static VALUE numeric_to_ruby(VALUE self)
00606 {
00607 Value const& value(rb2cxx::object<Value>(self));
00608 VALUE registry = value_get_registry(self);
00609 try {
00610 return typelib_to_ruby(value, registry, Qnil);
00611 } catch(Typelib::NullTypeFound) { }
00612 rb_raise(rb_eTypeError, "trying to convert 'void'");
00613 }
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624 static VALUE numeric_from_ruby(VALUE self, VALUE arg)
00625 {
00626 Value& value(rb2cxx::object<Value>(self));
00627 try {
00628 typelib_from_ruby(value, arg);
00629 return self;
00630 } catch(Typelib::UnsupportedType) { }
00631 rb_raise(rb_eTypeError, "cannot perform the requested convertion");
00632 }
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659 void typelib_ruby::Typelib_init_specialized_types()
00660 {
00661 VALUE mTypelib = rb_define_module("Typelib");
00662 cNumeric = rb_define_class_under(mTypelib, "NumericType", cType);
00663 rb_define_singleton_method(cNumeric, "integer?", RUBY_METHOD_FUNC(numeric_type_integer_p), 0);
00664 rb_define_singleton_method(cNumeric, "unsigned?", RUBY_METHOD_FUNC(numeric_type_unsigned_p), 0);
00665 rb_define_singleton_method(cNumeric, "size", RUBY_METHOD_FUNC(numeric_type_size), 0);
00666 rb_define_method(cNumeric, "typelib_to_ruby", RUBY_METHOD_FUNC(&numeric_to_ruby), 0);
00667 rb_define_method(cNumeric, "typelib_from_ruby", RUBY_METHOD_FUNC(&numeric_from_ruby), 1);
00668
00669 cOpaque = rb_define_class_under(mTypelib, "OpaqueType", cType);
00670 cNull = rb_define_class_under(mTypelib, "NullType", cType);
00671
00672 cIndirect = rb_define_class_under(mTypelib, "IndirectType", cType);
00673 rb_define_singleton_method(cIndirect, "deference", RUBY_METHOD_FUNC(indirect_type_deference), 0);
00674
00675 cPointer = rb_define_class_under(mTypelib, "PointerType", cIndirect);
00676 rb_define_method(cPointer, "deference", RUBY_METHOD_FUNC(pointer_deference), 0);
00677 rb_define_method(cPointer, "null?", RUBY_METHOD_FUNC(pointer_nil_p), 0);
00678
00679 cCompound = rb_define_class_under(mTypelib, "CompoundType", cType);
00680 rb_define_singleton_method(cCompound, "get_fields", RUBY_METHOD_FUNC(compound_get_fields), 0);
00681 rb_define_method(cCompound, "typelib_get_field", RUBY_METHOD_FUNC(compound_field_get), 1);
00682 rb_define_method(cCompound, "typelib_set_field", RUBY_METHOD_FUNC(compound_field_set), 2);
00683
00684 cEnum = rb_define_class_under(mTypelib, "EnumType", cType);
00685 rb_define_singleton_method(cEnum, "keys", RUBY_METHOD_FUNC(enum_keys), 0);
00686 rb_define_singleton_method(cEnum, "value_of", RUBY_METHOD_FUNC(enum_value_of), 1);
00687 rb_define_singleton_method(cEnum, "name_of", RUBY_METHOD_FUNC(enum_name_of), 1);
00688 rb_define_method(cEnum, "typelib_to_ruby", RUBY_METHOD_FUNC(&numeric_to_ruby), 0);
00689 rb_define_method(cEnum, "typelib_from_ruby", RUBY_METHOD_FUNC(&numeric_from_ruby), 1);
00690
00691 cArray = rb_define_class_under(mTypelib, "ArrayType", cIndirect);
00692 rb_define_singleton_method(cArray, "length", RUBY_METHOD_FUNC(array_class_length), 0);
00693 rb_define_method(cArray, "do_get", RUBY_METHOD_FUNC(array_get), -1);
00694 rb_define_method(cArray, "do_set", RUBY_METHOD_FUNC(array_set), 2);
00695 rb_define_method(cArray, "do_each", RUBY_METHOD_FUNC(array_do_each), 0);
00696 rb_define_method(cArray, "size", RUBY_METHOD_FUNC(array_size), 0);
00697
00698 cContainer = rb_define_class_under(mTypelib, "ContainerType", cIndirect);
00699 rb_define_singleton_method(cContainer, "container_kind", RUBY_METHOD_FUNC(container_kind), 0);
00700 rb_define_singleton_method(cContainer, "natural_size", RUBY_METHOD_FUNC(container_natural_size), 0);
00701 rb_define_singleton_method(cContainer, "random_access?", RUBY_METHOD_FUNC(container_random_access_p), 0);
00702 rb_define_method(cContainer, "length", RUBY_METHOD_FUNC(container_length), 0);
00703 rb_define_method(cContainer, "size", RUBY_METHOD_FUNC(container_length), 0);
00704 rb_define_method(cContainer, "do_clear", RUBY_METHOD_FUNC(container_clear), 0);
00705 rb_define_method(cContainer, "do_push", RUBY_METHOD_FUNC(container_do_push), 1);
00706 rb_define_method(cContainer, "do_get", RUBY_METHOD_FUNC(container_do_get), 1);
00707 rb_define_method(cContainer, "do_set", RUBY_METHOD_FUNC(container_do_set), 2);
00708 rb_define_method(cContainer, "do_each", RUBY_METHOD_FUNC(container_each), 0);
00709 rb_define_method(cContainer, "do_erase", RUBY_METHOD_FUNC(container_erase), 1);
00710 rb_define_method(cContainer, "do_delete_if", RUBY_METHOD_FUNC(container_delete_if), 0);
00711 }
00712