00001 #include "typelib.hh"
00002 #include <ruby.h>
00003
00004 #include <sstream>
00005 #include <limits>
00006 #include <typelib/value.hh>
00007 #include <typelib/registry.hh>
00008 #include <typelib/typevisitor.hh>
00009 #include <typelib/csvoutput.hh>
00010 #include <typelib/endianness.hh>
00011 #include <typelib/value_ops.hh>
00012 #include <typelib/typename.hh>
00013
00014 #include <iostream>
00015
00016 using namespace Typelib;
00017 using std::numeric_limits;
00018 using std::vector;
00019 using namespace typelib_ruby;
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 VALUE cxx2rb::value_wrap(Value v, VALUE registry, VALUE parent)
00036 {
00037 VALUE type = type_wrap(v.getType(), registry);
00038 VALUE ptr = memory_wrap(v.getData());
00039 VALUE wrapper = rb_funcall(type, rb_intern("wrap"), 1, ptr);
00040 rb_iv_set(wrapper, "@parent", parent);
00041 return wrapper;
00042 }
00043
00044 static VALUE value_allocate(Type const& type, VALUE registry)
00045 {
00046 VALUE rb_type = cxx2rb::type_wrap(type, registry);
00047 VALUE ptr = memory_allocate(type.getSize());
00048 memory_init(ptr, rb_type);
00049 VALUE wrapper = rb_funcall(rb_type, rb_intern("wrap"), 1, ptr);
00050 return wrapper;
00051 }
00052
00053 namespace typelib_ruby {
00054 VALUE cType = Qnil;
00055 VALUE cNumeric = Qnil;
00056 VALUE cOpaque = Qnil;
00057 VALUE cNull = Qnil;
00058 VALUE cIndirect = Qnil;
00059 VALUE cPointer = Qnil;
00060 VALUE cArray = Qnil;
00061 VALUE cCompound = Qnil;
00062 VALUE cEnum = Qnil;
00063 VALUE cContainer = Qnil;
00064 }
00065
00066 VALUE cxx2rb::class_of(Typelib::Type const& type)
00067 {
00068 using Typelib::Type;
00069 switch(type.getCategory()) {
00070 case Type::Numeric: return cNumeric;
00071 case Type::Compound: return cCompound;
00072 case Type::Pointer: return cPointer;
00073 case Type::Array: return cArray;
00074 case Type::Enum: return cEnum;
00075 case Type::Container: return cContainer;
00076 case Type::Opaque: return cOpaque;
00077 case Type::NullType: return cNull;
00078 default: return cType;
00079 }
00080 }
00081
00082 VALUE cxx2rb::type_wrap(Type const& type, VALUE registry)
00083 {
00084
00085
00086 WrapperMap& wrappers = rb2cxx::object<RbRegistry>(registry).wrappers;
00087
00088 WrapperMap::const_iterator it = wrappers.find(&type);
00089 if (it != wrappers.end())
00090 return it->second.second;
00091
00092 VALUE base = class_of(type);
00093 VALUE klass = rb_funcall(rb_cClass, rb_intern("new"), 1, base);
00094 VALUE rb_type = Data_Wrap_Struct(rb_cObject, 0, 0, const_cast<Type*>(&type));
00095 rb_iv_set(klass, "@registry", registry);
00096 rb_iv_set(klass, "@type", rb_type);
00097 rb_iv_set(klass, "@name", rb_str_new2(type.getName().c_str()));
00098 rb_iv_set(klass, "@null", (type.getCategory() == Type::NullType) ? Qtrue : Qfalse);
00099 rb_iv_set(klass, "@opaque", (type.getCategory() == Type::Opaque) ? Qtrue : Qfalse);
00100
00101 if (rb_respond_to(klass, rb_intern("subclass_initialize")))
00102 rb_funcall(klass, rb_intern("subclass_initialize"), 0);
00103
00104 wrappers.insert(std::make_pair(&type, std::make_pair(false, klass)));
00105 return klass;
00106 }
00107
00108
00109
00110
00111
00128 static VALUE type_to_csv(int argc, VALUE* argv, VALUE rbself)
00129 {
00130 VALUE basename = Qnil;
00131 VALUE separator = Qnil;
00132 rb_scan_args(argc, argv, "02", &basename, &separator);
00133
00134 std::string bname = "", sep = " ";
00135 if (!NIL_P(basename)) bname = StringValuePtr(basename);
00136 if (!NIL_P(separator)) sep = StringValuePtr(separator);
00137
00138 Type const& self(rb2cxx::object<Type>(rbself));
00139 std::ostringstream stream;
00140 stream << csv_header(self, bname, sep);
00141 std::string str = stream.str();
00142 return rb_str_new(str.c_str(), str.length());
00143 }
00144
00145
00146
00147
00148
00149
00150
00151 static VALUE typelib_do_basename(VALUE mod, VALUE name)
00152 {
00153 std::string result = Typelib::getTypename(StringValuePtr(name));
00154 return rb_str_new(result.c_str(), result.length());
00155 }
00156
00157
00158 static VALUE typelib_do_namespace(VALUE mod, VALUE name)
00159 {
00160 std::string result = Typelib::getNamespace(StringValuePtr(name));
00161 return rb_str_new(result.c_str(), result.length());
00162 }
00163
00164
00165 static VALUE typelib_do_split_name(VALUE mod, VALUE name)
00166 {
00167 std::list<std::string> splitted = Typelib::splitTypename(StringValuePtr(name));
00168 VALUE result = rb_ary_new();
00169 for (std::list<std::string>::const_iterator it = splitted.begin(); it != splitted.end(); ++it)
00170 rb_ary_push(result, rb_str_new(it->c_str(), it->length()));
00171 return result;
00172 }
00173
00174
00175
00176
00177
00178
00179
00180 static VALUE type_equal_operator(VALUE rbself, VALUE rbwith)
00181 {
00182 if (! rb_respond_to(rbwith, rb_intern("superclass")))
00183 return Qfalse;
00184 if (rb_funcall(rbself, rb_intern("superclass"), 0) != rb_funcall(rbwith, rb_intern("superclass"), 0))
00185 return Qfalse;
00186
00187 Type const& self(rb2cxx::object<Type>(rbself));
00188 Type const& with(rb2cxx::object<Type>(rbwith));
00189 bool result = (self == with) || self.isSame(with);
00190 return result ? Qtrue : Qfalse;
00191 }
00192
00193
00194
00195
00196
00197
00198 static VALUE type_size(VALUE self)
00199 {
00200 Type const& type(rb2cxx::object<Type>(self));
00201 return INT2FIX(type.getSize());
00202 }
00203
00204
00205
00206
00207
00208
00209
00210 static VALUE type_dependencies(VALUE self)
00211 {
00212 Type const& type(rb2cxx::object<Type>(self));
00213
00214 typedef std::set<Type const*> TypeSet;
00215 TypeSet dependencies = type.dependsOn();
00216 VALUE registry = type_get_registry(self);
00217
00218 VALUE result = rb_ary_new();
00219 for (TypeSet::const_iterator it = dependencies.begin(); it != dependencies.end(); ++it)
00220 rb_ary_push(result, cxx2rb::type_wrap(**it, registry));
00221 return result;
00222 }
00223
00224
00225
00226
00227
00228
00229
00230 static VALUE type_can_cast_to(VALUE self, VALUE to)
00231 {
00232 Type const& from_type(rb2cxx::object<Type>(self));
00233 Type const& to_type(rb2cxx::object<Type>(to));
00234 return from_type.canCastTo(to_type) ? Qtrue : Qfalse;
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244 static VALUE type_memory_layout(VALUE self, VALUE pointers, VALUE opaques, VALUE merge, VALUE remove_trailing_skips)
00245 {
00246 Type const& type(rb2cxx::object<Type>(self));
00247 VALUE registry = type_get_registry(self);
00248
00249 VALUE result = rb_ary_new();
00250
00251 VALUE rb_memcpy = ID2SYM(rb_intern("FLAG_MEMCPY"));
00252 VALUE rb_skip = ID2SYM(rb_intern("FLAG_SKIP"));
00253 VALUE rb_array = ID2SYM(rb_intern("FLAG_ARRAY"));
00254 VALUE rb_end = ID2SYM(rb_intern("FLAG_END"));
00255 VALUE rb_container = ID2SYM(rb_intern("FLAG_CONTAINER"));
00256
00257 try {
00258 MemoryLayout layout = Typelib::layout_of(type, RTEST(pointers), RTEST(opaques), RTEST(merge), RTEST(remove_trailing_skips));
00259
00260
00261 for (MemoryLayout::const_iterator it = layout.begin(); it != layout.end(); ++it)
00262 {
00263 switch(*it)
00264 {
00265 case MemLayout::FLAG_MEMCPY:
00266 rb_ary_push(result, rb_memcpy);
00267 rb_ary_push(result, LONG2NUM(*(++it)));
00268 break;
00269 case MemLayout::FLAG_SKIP:
00270 rb_ary_push(result, rb_skip);
00271 rb_ary_push(result, LONG2NUM(*(++it)));
00272 break;
00273 case MemLayout::FLAG_ARRAY:
00274 rb_ary_push(result, rb_array);
00275 rb_ary_push(result, LONG2NUM(*(++it)));
00276 break;
00277 case MemLayout::FLAG_END:
00278 rb_ary_push(result, rb_end);
00279 break;
00280 case MemLayout::FLAG_CONTAINER:
00281 rb_ary_push(result, rb_container);
00282 rb_ary_push(result, cxx2rb::type_wrap(*reinterpret_cast<Container*>(*(++it)), registry));
00283 break;
00284 default:
00285 rb_raise(rb_eArgError, "error encountered while parsing memory layout");
00286 }
00287 }
00288
00289 } catch(std::exception const& e) {
00290 rb_raise(rb_eArgError, e.what());
00291 }
00292
00293 return result;
00294 }
00295
00296
00297 static VALUE type_is_assignable(Type const& type)
00298 {
00299 switch(type.getCategory())
00300 {
00301 case Type::Numeric:
00302 return INT2FIX(1);
00303 case Type::Pointer:
00304 return type_is_assignable( dynamic_cast<Pointer const&>(type).getIndirection());
00305 case Type::Enum:
00306 return INT2FIX(1);
00307 default:
00308 return INT2FIX(0);
00309 }
00310
00311 }
00312
00313 VALUE typelib_ruby::type_get_registry(VALUE self)
00314 {
00315 return rb_iv_get(self, "@registry");
00316 }
00317
00318
00319
00320
00321
00322
00323
00324
00325 static void value_delete(void* self) { delete reinterpret_cast<Value*>(self); }
00326
00327 static VALUE value_alloc(VALUE klass)
00328 { return Data_Wrap_Struct(klass, 0, value_delete, new Value); }
00329
00330 static
00331 VALUE value_initialize(VALUE self, VALUE ptr)
00332 {
00333 Type const& t(rb2cxx::object<Type>(rb_class_of(self)));
00334
00335 if (NIL_P(ptr) || rb_obj_is_kind_of(ptr, rb_cString))
00336 {
00337 VALUE buffer = memory_allocate(t.getSize());
00338 memory_init(buffer, rb_class_of(self));
00339 if (! NIL_P(ptr))
00340 {
00341 char* ruby_buffer = StringValuePtr(ptr);
00342 vector<uint8_t> cxx_buffer(ruby_buffer, ruby_buffer + RSTRING_LEN(ptr));
00343 try { Typelib::load(Value(memory_cptr(buffer), t), cxx_buffer); }
00344 catch(std::exception const& e)
00345 { rb_raise(rb_eArgError, e.what()); }
00346 }
00347
00348 ptr = buffer;
00349 }
00350
00351
00352 rb_iv_set(self, "@ptr", ptr);
00353 Value& value = rb2cxx::object<Value>(self);
00354 value = Value(memory_cptr(ptr), t);
00355 return self;
00356 }
00357
00358 static
00359 VALUE value_address(VALUE self)
00360 {
00361 Value value = rb2cxx::object<Value>(self);
00362 return LONG2NUM((long)value.getData());
00363 }
00364
00365 static
00366 VALUE value_endian_swap(VALUE self)
00367 {
00368 Value& value = rb2cxx::object<Value>(self);
00369 CompileEndianSwapVisitor compiled;
00370 compiled.apply(value.getType());
00371
00372 VALUE registry = value_get_registry(self);
00373 VALUE result = value_allocate(value.getType(), registry);
00374 compiled.swap(value, rb2cxx::object<Value>(result));
00375 return result;
00376 }
00377
00378 static
00379 VALUE value_endian_swap_b(VALUE self, VALUE rb_compile)
00380 {
00381 Value& value = rb2cxx::object<Value>(self);
00382 endian_swap(value);
00383 return self;
00384 }
00385
00386 static
00387 VALUE value_do_cast(VALUE self, VALUE target_type)
00388 {
00389 Value& value = rb2cxx::object<Value>(self);
00390 Type const& to_type(rb2cxx::object<Type>(target_type));
00391
00392 if (value.getType() == to_type)
00393 return self;
00394
00395 VALUE registry = rb_iv_get(target_type, "@registry");
00396 Value casted(value.getData(), to_type);
00397 return cxx2rb::value_wrap(casted, registry, self);
00398 }
00399
00400
00401 static
00402 VALUE value_do_byte_array(VALUE self, VALUE pointers, VALUE opaques, VALUE merge, VALUE remove_trailing_skips)
00403 {
00404 Value& value = rb2cxx::object<Value>(self);
00405 MemoryLayout layout = Typelib::layout_of(value.getType(), RTEST(pointers), RTEST(opaques), RTEST(merge), RTEST(remove_trailing_skips));
00406
00407 vector<uint8_t> buffer;
00408 Typelib::dump(value, buffer, layout);
00409 return rb_str_new(reinterpret_cast<char*>(&buffer[0]), buffer.size());
00410 }
00411
00412
00413
00414
00415
00416
00417
00418 static
00419 VALUE value_marshalling_size(VALUE self)
00420 {
00421 Value& value = rb2cxx::object<Value>(self);
00422 return INT2NUM(Typelib::getDumpSize(value));
00423 }
00424
00425 VALUE value_memory_eql_p(VALUE rbself, VALUE rbwith)
00426 {
00427 Value& self = rb2cxx::object<Value>(rbself);
00428 Value& with = rb2cxx::object<Value>(rbwith);
00429
00430 if (self.getData() == with.getData())
00431 return Qtrue;
00432
00433
00434 Type const& type = self.getType();
00435 return memcmp(self.getData(), with.getData(), type.getSize()) == 0 ? Qtrue : Qfalse;
00436 }
00437
00438 VALUE typelib_ruby::value_get_registry(VALUE self)
00439 {
00440 VALUE type = rb_funcall(self, rb_intern("class"), 0);
00441 return rb_iv_get(type, "@registry");
00442 }
00443
00451 static VALUE value_to_csv(int argc, VALUE* argv, VALUE self)
00452 {
00453 VALUE separator = Qnil;
00454 rb_scan_args(argc, argv, "01", &separator);
00455
00456 Value const& value(rb2cxx::object<Value>(self));
00457 std::string sep = " ";
00458 if (!NIL_P(separator)) sep = StringValuePtr(separator);
00459
00460 std::ostringstream stream;
00461 stream << csv(value.getType(), value.getData(), sep);
00462 std::string str = stream.str();
00463 return rb_str_new(str.c_str(), str.length());
00464 }
00465
00466
00467 static VALUE value_zero(VALUE self)
00468 {
00469 Value const& value(rb2cxx::object<Value>(self));
00470 Typelib::zero(value);
00471 return self;
00472 }
00473
00474 static VALUE typelib_do_copy(VALUE, VALUE to, VALUE from)
00475 {
00476 Value v_from = rb2cxx::object<Value>(from);
00477 Value v_to = rb2cxx::object<Value>(to);
00478
00479 if (v_from.getType() != v_to.getType())
00480 {
00481
00482 if (!v_from.getType().canCastTo(v_to.getType()))
00483 rb_raise(rb_eArgError, "cannot copy: types are not compatible");
00484 }
00485 Typelib::copy(v_to.getData(), v_from.getData(), v_from.getType());
00486 return to;
00487 }
00488
00489
00490
00491
00492
00493
00494
00495 static VALUE typelib_compare(VALUE, VALUE to, VALUE from)
00496 {
00497 Value v_from = rb2cxx::object<Value>(from);
00498 Value v_to = rb2cxx::object<Value>(to);
00499
00500 if (v_from.getType() != v_to.getType())
00501 {
00502
00503 if (!v_from.getType().canCastTo(v_to.getType()))
00504 rb_raise(rb_eArgError, "cannot compare: %s and %s are not compatible types",
00505 v_from.getType().getName().c_str(),
00506 v_to.getType().getName().c_str());
00507 }
00508 try {
00509 bool result = Typelib::compare(v_to.getData(), v_from.getData(), v_from.getType());
00510 return result ? Qtrue : Qfalse;
00511 } catch(std::exception const& e) {
00512 rb_raise(rb_eArgError, e.what());
00513 }
00514 }
00515
00516
00517 void typelib_ruby::Typelib_init_values()
00518 {
00519 VALUE mTypelib = rb_define_module("Typelib");
00520 rb_define_singleton_method(mTypelib, "do_copy", RUBY_METHOD_FUNC(typelib_do_copy), 2);
00521 rb_define_singleton_method(mTypelib, "compare", RUBY_METHOD_FUNC(typelib_compare), 2);
00522
00523 cType = rb_define_class_under(mTypelib, "Type", rb_cObject);
00524 rb_define_alloc_func(cType, value_alloc);
00525 rb_define_singleton_method(cType, "==", RUBY_METHOD_FUNC(type_equal_operator), 1);
00526 rb_define_singleton_method(cType, "size", RUBY_METHOD_FUNC(&type_size), 0);
00527 rb_define_singleton_method(cType, "do_memory_layout", RUBY_METHOD_FUNC(&type_memory_layout), 4);
00528 rb_define_singleton_method(cType, "dependencies", RUBY_METHOD_FUNC(&type_dependencies), 0);
00529 rb_define_singleton_method(cType, "casts_to?", RUBY_METHOD_FUNC(&type_can_cast_to), 1);
00530 rb_define_method(cType, "__initialize__", RUBY_METHOD_FUNC(&value_initialize), 1);
00531 rb_define_method(cType, "zero!", RUBY_METHOD_FUNC(&value_zero), 0);
00532 rb_define_method(cType, "memory_eql?", RUBY_METHOD_FUNC(&value_memory_eql_p), 1);
00533 rb_define_method(cType, "endian_swap", RUBY_METHOD_FUNC(&value_endian_swap), 0);
00534 rb_define_method(cType, "endian_swap!", RUBY_METHOD_FUNC(&value_endian_swap_b), 0);
00535 rb_define_method(cType, "zone_address", RUBY_METHOD_FUNC(&value_address), 0);
00536 rb_define_method(cType, "do_cast", RUBY_METHOD_FUNC(&value_do_cast), 1);
00537
00538 rb_define_singleton_method(mTypelib, "do_basename", RUBY_METHOD_FUNC(typelib_do_basename), 1);
00539 rb_define_singleton_method(mTypelib, "do_namespace", RUBY_METHOD_FUNC(typelib_do_namespace), 1);
00540 rb_define_singleton_method(mTypelib, "split_typename", RUBY_METHOD_FUNC(typelib_do_split_name), 1);
00541
00542 rb_define_singleton_method(cType, "to_csv", RUBY_METHOD_FUNC(type_to_csv), -1);
00543 rb_define_method(cType, "to_csv", RUBY_METHOD_FUNC(value_to_csv), -1);
00544 rb_define_method(cType, "do_byte_array", RUBY_METHOD_FUNC(value_do_byte_array), 4);
00545 rb_define_method(cType, "marshalling_size", RUBY_METHOD_FUNC(value_marshalling_size), 0);
00546
00547 Typelib_init_specialized_types();
00548 }
00549