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