00001 #include "typelib.hh"
00002
00003 #include <typelib/pluginmanager.hh>
00004 #include <typelib/importer.hh>
00005 #include <typelib/exporter.hh>
00006 #include <typelib/registryiterator.hh>
00007 #include <lang/csupport/standard_types.hh>
00008 #include <typelib/utilmm/configset.hh>
00009 #include <set>
00010
00011 using namespace Typelib;
00012 using utilmm::config_set;
00013 using namespace std;
00014 using namespace typelib_ruby;
00015 using cxx2rb::RbRegistry;
00016
00017
00018 namespace typelib_ruby {
00019 VALUE cRegistry = Qnil;
00020 VALUE eNotFound = Qnil;
00021 }
00022
00023
00024
00025
00026
00027
00028
00029
00030 static
00031 void registry_free(void* ptr)
00032 {
00033 using cxx2rb::WrapperMap;
00034 RbRegistry* rbregistry = reinterpret_cast<RbRegistry*>(ptr);
00035 WrapperMap& wrappers = rbregistry->wrappers;
00036 for (WrapperMap::iterator it = wrappers.begin(); it != wrappers.end(); ++it)
00037 {
00038 if (it->second.first)
00039 delete it->first;
00040 }
00041
00042 delete rbregistry;
00043 }
00044
00045 static
00046 void registry_mark(void* ptr)
00047 {
00048 using cxx2rb::WrapperMap;
00049 WrapperMap const& wrappers = reinterpret_cast<RbRegistry const*>(ptr)->wrappers;
00050 for (WrapperMap::const_iterator it = wrappers.begin(); it != wrappers.end(); ++it)
00051 rb_gc_mark(it->second.second);
00052 }
00053
00054 static
00055 VALUE registry_wrap(VALUE klass, Registry* registry)
00056 {
00057 return Data_Wrap_Struct(klass, registry_mark, registry_free, new RbRegistry(registry));
00058 }
00059
00060 static
00061 VALUE registry_alloc(VALUE klass)
00062 {
00063 Registry* registry = new Registry;
00064 return registry_wrap(klass, registry);
00065 }
00066
00067
00068 static
00069 VALUE registry_includes_p(VALUE self, VALUE name)
00070 {
00071 Registry& registry = rb2cxx::object<Registry>(self);
00072 Type const* type = registry.get( StringValuePtr(name) );
00073 return type ? Qtrue : Qfalse;
00074 }
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 static
00085 VALUE registry_remove(VALUE self, VALUE rbtype)
00086 {
00087 RbRegistry& rbregistry = rb2cxx::object<RbRegistry>(self);
00088 Registry& registry = *(rbregistry.registry);
00089 Type const& type(rb2cxx::object<Type>(rbtype));
00090 std::set<Type*> deleted = registry.remove(type);
00091
00092 VALUE result = rb_ary_new();
00093 std::set<Type*>::iterator it, end;
00094 for (it = deleted.begin(); it != deleted.end(); ++it)
00095 {
00096 rb_ary_push(result, cxx2rb::type_wrap(**it, self));
00097 cxx2rb::WrapperMap::iterator wrapper_it = rbregistry.wrappers.find(*it);
00098 wrapper_it->second.first = true;
00099 }
00100
00101 return result;
00102 }
00103
00104
00105
00106
00107
00108
00109 static
00110 VALUE registry_source_id_of(VALUE self, VALUE rbtype)
00111 {
00112 RbRegistry& rbregistry = rb2cxx::object<RbRegistry>(self);
00113 Registry& registry = *(rbregistry.registry);
00114 Type const& type(rb2cxx::object<Type>(rbtype));
00115
00116 RegistryIterator it = registry.find(type.getName());
00117 if (it == registry.end())
00118 rb_raise(rb_eArgError, "this registry has no type called %s", type.getName().c_str());
00119
00120 std::string source = it.getSource();
00121 if (source.empty()) return Qnil;
00122 return rb_str_new(it.getSource().c_str(), it.getSource().length());
00123 }
00124
00125
00126
00127
00128
00129
00130
00131
00132 static
00133 VALUE registry_reverse_depends(VALUE self, VALUE rbtype)
00134 {
00135 Registry const& registry = rb2cxx::object<Registry>(self);
00136 Type const& type(rb2cxx::object<Type>(rbtype));
00137 std::set<Type const*> rdeps = registry.reverseDepends(type);
00138
00139 VALUE result = rb_ary_new();
00140 std::set<Type const*>::iterator it, end;
00141 for (it = rdeps.begin(); it != rdeps.end(); ++it)
00142 rb_ary_push(result, cxx2rb::type_wrap(**it, self));
00143
00144 return result;
00145 }
00146
00147 static
00148 VALUE registry_do_get(VALUE self, VALUE name)
00149 {
00150 Registry& registry = rb2cxx::object<Registry>(self);
00151 Type const* type = registry.get( StringValuePtr(name) );
00152
00153 if (! type)
00154 rb_raise(eNotFound, "there is no type in this registry with the name '%s'", StringValuePtr(name));
00155 return cxx2rb::type_wrap(*type, self);
00156 }
00157
00158 static
00159 VALUE registry_do_build(int argc, VALUE* argv, VALUE self)
00160 {
00161 VALUE name = argv[0];
00162 int size = 0;
00163 if (argc == 0 || argc > 2)
00164 rb_raise(rb_eArgError, "expected one or two arguments, got %i", argc);
00165 else if (argc == 2)
00166 size = NUM2INT(argv[1]);
00167
00168 Registry& registry = rb2cxx::object<Registry>(self);
00169 try {
00170 Type const* type = registry.build( StringValuePtr(name), size );
00171 if (! type)
00172 rb_raise(eNotFound, "cannot find %s in registry", StringValuePtr(name));
00173 return cxx2rb::type_wrap(*type, self);
00174 }
00175 catch(std::exception const& e) { rb_raise(rb_eRuntimeError, "%s", e.what()); }
00176 }
00177
00178
00179
00180
00181
00182
00183
00184 static
00185 VALUE registry_alias(VALUE self, VALUE name, VALUE aliased)
00186 {
00187 Registry& registry = rb2cxx::object<Registry>(self);
00188
00189 try {
00190 registry.alias(StringValuePtr(aliased), StringValuePtr(name));
00191 return self;
00192 } catch(BadName) {
00193 rb_raise(rb_eArgError, "invalid type name %s", StringValuePtr(name));
00194 } catch(Undefined) {
00195 rb_raise(eNotFound, "there is not type in this registry with the name '%s'", StringValuePtr(aliased));
00196 }
00197 }
00198
00199 static
00200 void setup_configset_from_option_array(config_set& config, VALUE options)
00201 {
00202 int options_length = RARRAY_LEN(options);
00203 for (int i = 0; i < options_length; ++i)
00204 {
00205 VALUE entry = RARRAY_PTR(options)[i];
00206 VALUE k = RARRAY_PTR(entry)[0];
00207 VALUE v = RARRAY_PTR(entry)[1];
00208
00209 if ( rb_obj_is_kind_of(v, rb_cArray) )
00210 {
00211 VALUE first_el = rb_ary_entry(v, 0);
00212 if (rb_obj_is_kind_of(first_el, rb_cArray))
00213 {
00214
00215 for (int j = 0; j < RARRAY_LEN(v); ++j)
00216 {
00217 config_set* child = new config_set;
00218 setup_configset_from_option_array(*child, rb_ary_entry(v, j));
00219 config.insert(StringValuePtr(k), child);
00220 }
00221 }
00222 else
00223 {
00224 for (int j = 0; j < RARRAY_LEN(v); ++j)
00225 {
00226 VALUE value = rb_ary_entry(v, j);
00227 config.insert(StringValuePtr(k), StringValuePtr(value));
00228 }
00229 }
00230 }
00231 else if (TYPE(v) == T_TRUE || TYPE(v) == T_FALSE)
00232 config.set(StringValuePtr(k), RTEST(v) ? "true" : "false");
00233 else
00234 config.set(StringValuePtr(k), StringValuePtr(v));
00235 }
00236 }
00237
00238
00239
00240
00241
00242 static
00243 VALUE registry_import(VALUE self, VALUE file, VALUE kind, VALUE merge, VALUE options)
00244 {
00245 Registry& registry = rb2cxx::object<Registry>(self);
00246
00247 config_set config;
00248 setup_configset_from_option_array(config, options);
00249
00250 std::string error_string;
00251 try {
00252 if (RTEST(merge))
00253 {
00254 Registry temp;
00255 PluginManager::load(StringValuePtr(kind), StringValuePtr(file), config, temp);
00256 registry.merge(temp);
00257 }
00258 else
00259 PluginManager::load(StringValuePtr(kind), StringValuePtr(file), config, registry);
00260 return Qnil;
00261 }
00262 catch(boost::bad_lexical_cast e) { error_string = e.what(); }
00263 catch(std::exception const& e) { error_string = e.what(); }
00264
00265 rb_raise(rb_eRuntimeError, "%s", error_string.c_str());
00266 }
00267
00268
00269
00270
00271
00272 static
00273 VALUE registry_export(VALUE self, VALUE kind, VALUE options)
00274 {
00275 Registry& registry = rb2cxx::object<Registry>(self);
00276
00277 config_set config;
00278 setup_configset_from_option_array(config, options);
00279
00280 string error_message;
00281 try {
00282 std::string exported = PluginManager::save(StringValuePtr(kind), config, registry);
00283 return rb_str_new(exported.c_str(), exported.length());
00284 }
00285 catch (std::exception const& e) { error_message = e.what(); }
00286 rb_raise(rb_eRuntimeError, "%s", error_message.c_str());
00287 }
00288
00289
00290
00291
00292
00293
00294
00295
00296 static
00297 VALUE registry_merge(VALUE self, VALUE rb_merged)
00298 {
00299 std::string error_string;
00300
00301 Registry& registry = rb2cxx::object<Registry>(self);
00302 Registry& merged = rb2cxx::object<Registry>(rb_merged);
00303 try {
00304 registry.merge(merged);
00305 return self;
00306 }
00307 catch(std::exception const& e) { error_string = e.what(); }
00308 rb_raise(rb_eRuntimeError, "%s", error_string.c_str());
00309 }
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319 static
00320 VALUE registry_resize(VALUE self, VALUE new_sizes)
00321 {
00322 Registry& registry = rb2cxx::object<Registry>(self);
00323
00324 std::map<std::string, size_t> sizes;
00325 size_t map_size = RARRAY_LEN(new_sizes);
00326 VALUE* map_values = RARRAY_PTR(new_sizes);
00327 for (size_t i = 0; i < map_size; ++i)
00328 {
00329 VALUE* pair = RARRAY_PTR(map_values[i]);
00330 sizes.insert(std::make_pair(
00331 StringValuePtr(pair[0]),
00332 NUM2INT(pair[1])));
00333 }
00334 try {
00335 registry.resize(sizes);
00336 return Qnil;
00337 }
00338 catch(std::exception const& e) {
00339 rb_raise(rb_eRuntimeError, "%s", e.what());
00340 }
00341 }
00342
00343 static
00344 VALUE registry_minimal(VALUE self, VALUE rb_auto, VALUE with_aliases)
00345 {
00346 std::string error_string;
00347 Registry& registry = rb2cxx::object<Registry>(self);
00348
00349 if (rb_obj_is_kind_of(rb_auto, rb_cString))
00350 {
00351 try {
00352 Registry* result = registry.minimal(StringValuePtr(rb_auto), RTEST(with_aliases));
00353 return registry_wrap(cRegistry, result);
00354 }
00355 catch(std::exception const& e)
00356 { rb_raise(rb_eRuntimeError, "%s", e.what()); }
00357 }
00358 else
00359 {
00360 Registry& auto_types = rb2cxx::object<Registry>(rb_auto);
00361 try {
00362 Registry* result = registry.minimal(auto_types);
00363 return registry_wrap(cRegistry, result);
00364 }
00365 catch(std::exception const& e)
00366 { rb_raise(rb_eRuntimeError, "%s", e.what()); }
00367 }
00368 }
00369
00370
00371 static void yield_types(VALUE self, bool with_aliases, RegistryIterator it, RegistryIterator end)
00372 {
00373 if (with_aliases)
00374 {
00375 for (; it != end; ++it)
00376 {
00377 std::string const& type_name = it.getName();
00378 VALUE rb_type_name = rb_str_new(type_name.c_str(), type_name.length());
00379 rb_yield_values(2, rb_type_name, cxx2rb::type_wrap(*it, self));
00380 }
00381 }
00382 else
00383 {
00384 for (; it != end; ++it)
00385 {
00386 if (!it.isAlias())
00387 rb_yield(cxx2rb::type_wrap(*it, self));
00388 }
00389 }
00390 }
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408 static
00409 VALUE registry_each_type(VALUE self, VALUE filter_, VALUE with_aliases_)
00410 {
00411 Registry& registry = rb2cxx::object<Registry>(self);
00412 bool with_aliases = RTEST(with_aliases_);
00413 std::string filter;
00414 if (RTEST(filter_))
00415 filter = StringValuePtr(filter_);
00416
00417 try
00418 {
00419 if (filter.empty())
00420 yield_types(self, with_aliases, registry.begin(), registry.end());
00421 else
00422 yield_types(self, with_aliases, registry.begin(filter), registry.end(filter));
00423
00424 return self;
00425 }
00426 catch(std::exception const& e)
00427 {
00428 rb_raise(rb_eRuntimeError, "%s", e.what());
00429 }
00430 }
00431
00432
00433
00434
00435
00436
00437
00438 static
00439 VALUE registry_merge_xml(VALUE rb_registry, VALUE xml)
00440 {
00441 Registry& registry = rb2cxx::object<Registry>(rb_registry);
00442
00443 std::istringstream istream(StringValuePtr(xml));
00444 config_set config;
00445 try { PluginManager::load("tlb", istream, config, registry); }
00446 catch(boost::bad_lexical_cast e)
00447 { rb_raise(rb_eArgError, "cannot load xml: %s", e.what()); }
00448 catch(std::exception const& e)
00449 { rb_raise(rb_eArgError, "cannot load xml: %s", e.what()); }
00450
00451 return rb_registry;
00452 }
00453
00454
00455
00456
00457
00458
00459
00460 static VALUE registry_aliases_of(VALUE self, VALUE type_)
00461 {
00462 Registry& registry = rb2cxx::object<Registry>(self);
00463 Type const& type(rb2cxx::object<Type>(type_));
00464 std::set<std::string> aliases =
00465 registry.getAliasesOf(type);
00466
00467 VALUE result = rb_ary_new();
00468 for (set<string>::const_iterator it = aliases.begin(); it != aliases.end(); ++it)
00469 rb_ary_push(result, rb_str_new(it->c_str(), it->length()));
00470 return result;
00471 }
00472
00473
00474
00475
00476
00477
00478
00479 static VALUE registry_clear_aliases(VALUE self)
00480 {
00481 Registry& registry = rb2cxx::object<Registry>(self);
00482 registry.clearAliases();
00483 return Qnil;
00484 }
00485
00486
00487
00488
00489
00490
00491
00492 static VALUE registry_size(VALUE self)
00493 {
00494 Registry& registry = rb2cxx::object<Registry>(self);
00495 return INT2NUM(registry.size());
00496 }
00497
00498
00499
00500
00501
00502
00503
00504 static VALUE registry_available_container(VALUE registry_module)
00505 {
00506 Typelib::Container::AvailableContainers containers =
00507 Typelib::Container::availableContainers();
00508
00509 VALUE result = rb_ary_new();
00510 Typelib::Container::AvailableContainers::const_iterator
00511 it = containers.begin(),
00512 end = containers.end();
00513
00514 while (it != end)
00515 {
00516 std::string name = it->first;
00517 rb_ary_push(result, rb_str_new(name.c_str(), name.length()));
00518 ++it;
00519 }
00520 return result;
00521 }
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535 static VALUE registry_define_container(VALUE registry, VALUE kind, VALUE element, VALUE _size)
00536 {
00537 Registry& reg = rb2cxx::object<Registry>(registry);
00538 Type const& element_type(rb2cxx::object<Type>(element));
00539
00540 if (!reg.isIncluded(element_type))
00541 rb_raise(rb_eArgError, "the given type object comes from a different type registry");
00542
00543 try {
00544 Container const& new_type = Container::createContainer(reg, StringValuePtr(kind), element_type);
00545 size_t size = NUM2INT(_size);
00546 if (size != 0)
00547 reg.get_(new_type).setSize(size);
00548 return cxx2rb::type_wrap(new_type, registry);
00549 } catch(Typelib::UnknownContainer) {
00550 rb_raise(eNotFound, "%s is not a known container type", StringValuePtr(kind));
00551 }
00552 }
00553
00554
00555
00556
00557
00558
00559
00560 static VALUE registry_add_standard_cxx_types(VALUE klass, VALUE registry)
00561 {
00562 Registry& reg = rb2cxx::object<Registry>(registry);
00563 try { Typelib::CXX::addStandardTypes(reg); }
00564 catch(Typelib::AlreadyDefined e)
00565 { rb_raise(rb_eArgError, "%s", e.what()); }
00566 return registry;
00567 }
00568
00569
00570
00571
00572
00573
00574
00575 static VALUE registry_create_compound(VALUE registry, VALUE name, VALUE field_defs, VALUE _size)
00576 {
00577 Registry& reg = rb2cxx::object<Registry>(registry);
00578
00579 std::auto_ptr<Typelib::Compound> new_t(new Typelib::Compound(StringValuePtr(name)));
00580
00581 int field_count = RARRAY_LEN(field_defs);
00582 for (int i = 0; i < field_count; ++i)
00583 {
00584 VALUE field = rb_ary_entry(field_defs, i);
00585
00586 VALUE rb_name = rb_ary_entry(field, 0);
00587 std::string field_name(StringValuePtr(rb_name));
00588 Typelib::Type& field_type(rb2cxx::object<Type>(rb_ary_entry(field, 1)));
00589 int offset(NUM2INT(rb_ary_entry(field, 2)));
00590 new_t->addField(field_name, field_type, offset);
00591 }
00592
00593 Typelib::Compound* type = new_t.release();
00594 size_t size = NUM2INT(_size);
00595 if (size != 0)
00596 type->setSize(size);
00597 try { reg.add(type, true, ""); }
00598 catch(std::runtime_error e) { rb_raise(rb_eArgError, "%s", e.what()); }
00599 return cxx2rb::type_wrap(*type, registry);
00600 }
00601
00602
00603
00604
00605
00606
00607
00608 static VALUE registry_create_enum(VALUE registry, VALUE name, VALUE symbol_defs, VALUE _size)
00609 {
00610 Registry& reg = rb2cxx::object<Registry>(registry);
00611
00612 std::auto_ptr<Typelib::Enum> new_t(new Typelib::Enum(StringValuePtr(name)));
00613
00614 int symbol_count = RARRAY_LEN(symbol_defs);
00615 for (int i = 0; i < symbol_count; ++i)
00616 {
00617 VALUE sym = rb_ary_entry(symbol_defs, i);
00618
00619 VALUE rb_name = rb_ary_entry(sym, 0);
00620 std::string sym_name(StringValuePtr(rb_name));
00621 int sym_value(NUM2INT(rb_ary_entry(sym, 1)));
00622 new_t->add(sym_name, sym_value);
00623 }
00624
00625 Typelib::Enum* type = new_t.release();
00626 size_t size = NUM2INT(_size);
00627 if (size != 0) type->setSize(size);
00628 try { reg.add(type, true, ""); }
00629 catch(std::runtime_error e) { rb_raise(rb_eArgError, "%s", e.what()); }
00630 return cxx2rb::type_wrap(*type, registry);
00631 }
00632
00633
00634
00635
00636
00637
00638
00639 static VALUE registry_create_opaque(VALUE registry, VALUE _name, VALUE _size)
00640 {
00641 Registry& reg = rb2cxx::object<Registry>(registry);
00642 Typelib::Type* type = new Typelib::OpaqueType(StringValuePtr(_name), NUM2INT(_size));
00643 try { reg.add(type, true, ""); }
00644 catch(std::runtime_error e) { rb_raise(rb_eArgError, "%s", e.what()); }
00645 return cxx2rb::type_wrap(*type, registry);
00646 }
00647
00648
00649
00650
00651
00652
00653
00654 static VALUE registry_create_null(VALUE registry, VALUE _name)
00655 {
00656 Registry& reg = rb2cxx::object<Registry>(registry);
00657 Typelib::Type* type = new Typelib::NullType(StringValuePtr(_name));
00658 try { reg.add(type, true, ""); }
00659 catch(std::runtime_error e) { rb_raise(rb_eArgError, "%s", e.what()); }
00660 return cxx2rb::type_wrap(*type, registry);
00661 }
00662
00663 void typelib_ruby::Typelib_init_registry()
00664 {
00665 VALUE mTypelib = rb_define_module("Typelib");
00666 cRegistry = rb_define_class_under(mTypelib, "Registry", rb_cObject);
00667 eNotFound = rb_define_class_under(mTypelib, "NotFound", rb_eRuntimeError);
00668 rb_define_alloc_func(cRegistry, registry_alloc);
00669 rb_define_method(cRegistry, "size", RUBY_METHOD_FUNC(registry_size), 0);
00670 rb_define_method(cRegistry, "get", RUBY_METHOD_FUNC(registry_do_get), 1);
00671 rb_define_method(cRegistry, "build", RUBY_METHOD_FUNC(registry_do_build), -1);
00672 rb_define_method(cRegistry, "each_type", RUBY_METHOD_FUNC(registry_each_type), 2);
00673
00674
00675 rb_define_method(cRegistry, "do_import", RUBY_METHOD_FUNC(registry_import), 4);
00676 rb_define_method(cRegistry, "do_export", RUBY_METHOD_FUNC(registry_export), 2);
00677 rb_define_method(cRegistry, "merge_xml", RUBY_METHOD_FUNC(registry_merge_xml), 1);
00678 rb_define_method(cRegistry, "alias", RUBY_METHOD_FUNC(registry_alias), 2);
00679 rb_define_method(cRegistry, "clear_aliases", RUBY_METHOD_FUNC(registry_clear_aliases), 0);
00680 rb_define_method(cRegistry, "aliases_of", RUBY_METHOD_FUNC(registry_aliases_of), 1);
00681 rb_define_method(cRegistry, "merge", RUBY_METHOD_FUNC(registry_merge), 1);
00682 rb_define_method(cRegistry, "do_minimal", RUBY_METHOD_FUNC(registry_minimal), 2);
00683 rb_define_method(cRegistry, "includes?", RUBY_METHOD_FUNC(registry_includes_p), 1);
00684 rb_define_method(cRegistry, "do_resize", RUBY_METHOD_FUNC(registry_resize), 1);
00685 rb_define_method(cRegistry, "reverse_depends", RUBY_METHOD_FUNC(registry_reverse_depends), 1);
00686 rb_define_method(cRegistry, "remove", RUBY_METHOD_FUNC(registry_remove), 1);
00687 rb_define_method(cRegistry, "source_id_of", RUBY_METHOD_FUNC(registry_source_id_of), 1);
00688 rb_define_method(cRegistry, "do_create_compound", RUBY_METHOD_FUNC(registry_create_compound), 3);
00689 rb_define_method(cRegistry, "do_create_enum", RUBY_METHOD_FUNC(registry_create_enum), 3);
00690 rb_define_method(cRegistry, "create_opaque", RUBY_METHOD_FUNC(registry_create_opaque), 2);
00691 rb_define_method(cRegistry, "create_null", RUBY_METHOD_FUNC(registry_create_null), 1);
00692
00693 rb_define_singleton_method(cRegistry, "add_standard_cxx_types", RUBY_METHOD_FUNC(registry_add_standard_cxx_types), 1);
00694
00695 rb_define_singleton_method(cRegistry, "available_containers", RUBY_METHOD_FUNC(registry_available_container), 0);
00696 rb_define_method(cRegistry, "define_container", RUBY_METHOD_FUNC(registry_define_container), 3);
00697 }
00698