value.cc
Go to the documentation of this file.
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 void* value_root_ptr(VALUE value)
00022 {
00023     VALUE parent = Qnil;
00024     while (RTEST(value))
00025     {
00026         parent = value;
00027         value = rb_iv_get(value, "@parent");
00028     }
00029     if (RTEST(parent))
00030     {
00031         Value v = rb2cxx::object<Value>(parent);
00032         return v.getData();
00033     }
00034     else return NULL;
00035 }
00036 
00037 /* There are constraints when creating a Ruby wrapper for a Type, mainly
00038  * for avoiding GC issues. This function does the work.
00039  *
00040  * The main issue is that Ruby/DL does not keep refcounters on memory.
00041  * Instead, it returns always the same DLPtr object for a given memory
00042  * pointer. Problems arise when one of the two following situations are met:
00043  * * we reference a memory zone inside another memory zone (for instance,
00044  *   an array element or a structure field). In that case, the DLPtr object
00045  *   must not free the allocated zone. 
00046  * * two Typelib objects reference the same memory zone (first array
00047  *   element or first field of a structure). In that case, we must reuse the
00048  *   same DLPtr object, or DL will override the free function of the other
00049  *   DLPtr object -- which is obviously wrong, but nevertheless done.
00050  */
00051 VALUE cxx2rb::value_wrap(Value v, VALUE registry, VALUE parent)
00052 {
00053     VALUE type = type_wrap(v.getType(), registry);
00054 #   ifdef VERBOSE
00055     Value parent_value = rb2cxx::object<Value>(parent);
00056     fprintf(stderr, "wrapping Typelib::Value %p from C++, type=%s, parent=%p and root=%p\n", v.getData(), v.getType().getName().c_str(), parent_value.getData(), value_root_ptr(parent));
00057 #   endif
00058     VALUE ptr  = memory_wrap(v.getData(), false, value_root_ptr(parent));
00059     VALUE wrapper = rb_funcall(type, rb_intern("wrap"), 1, ptr);
00060 
00061     rb_iv_set(wrapper, "@parent", parent);
00062     rb_iv_set(wrapper, "@__typelib_invalidated", Qfalse);
00063     return wrapper;
00064 }
00065 
00066 static VALUE value_allocate(Type const& type, VALUE registry)
00067 {
00068     VALUE rb_type = cxx2rb::type_wrap(type, registry);
00069 #   ifdef VERBOSE
00070     fprintf(stderr, "allocating new value of type %s\n", type.getName().c_str());
00071 #   endif
00072     VALUE ptr     = memory_allocate(type.getSize());
00073     memory_init(ptr, rb_type);
00074     VALUE wrapper = rb_funcall(rb_type, rb_intern("wrap"), 1, ptr);
00075     return wrapper;
00076 }
00077 
00078 namespace typelib_ruby {
00079     VALUE cType  = Qnil;
00080     VALUE cNumeric       = Qnil;
00081     VALUE cOpaque        = Qnil;
00082     VALUE cNull  = Qnil;
00083     VALUE cIndirect  = Qnil;
00084     VALUE cPointer   = Qnil;
00085     VALUE cArray     = Qnil;
00086     VALUE cCompound  = Qnil;
00087     VALUE cEnum      = Qnil;
00088     VALUE cContainer = Qnil;
00089 }
00090 
00091 VALUE cxx2rb::class_of(Typelib::Type const& type)
00092 {
00093     using Typelib::Type;
00094     switch(type.getCategory()) {
00095         case Type::Numeric:     return cNumeric;
00096         case Type::Compound:    return cCompound;
00097         case Type::Pointer:     return cPointer;
00098         case Type::Array:       return cArray;
00099         case Type::Enum:        return cEnum;
00100         case Type::Container:   return cContainer;
00101         case Type::Opaque:      return cOpaque;
00102         case Type::NullType:    return cNull;
00103         default:                return cType;
00104     }
00105 }
00106 
00107 VALUE cxx2rb::type_wrap(Type const& type, VALUE registry)
00108 {
00109     // Type objects are unique, we can register Ruby wrappers based
00110     // on the type pointer (instead of using names)
00111     WrapperMap& wrappers = rb2cxx::object<RbRegistry>(registry).wrappers;
00112 
00113     WrapperMap::const_iterator it = wrappers.find(&type);
00114     if (it != wrappers.end())
00115         return it->second.second;
00116 
00117     VALUE base  = class_of(type);
00118     VALUE klass = rb_funcall(rb_cClass, rb_intern("new"), 1, base);
00119     VALUE rb_type = Data_Wrap_Struct(rb_cObject, 0, 0, const_cast<Type*>(&type));
00120     rb_iv_set(klass, "@registry", registry);
00121     rb_iv_set(klass, "@type", rb_type);
00122     rb_iv_set(klass, "@name", rb_str_new2(type.getName().c_str()));
00123     rb_iv_set(klass, "@null", (type.getCategory() == Type::NullType) ? Qtrue : Qfalse);
00124     rb_iv_set(klass, "@opaque", (type.getCategory() == Type::Opaque) ? Qtrue : Qfalse);
00125     rb_iv_set(klass, "@metadata", cxx2rb::metadata_wrap(type.getMetaData()));
00126 
00127     if (rb_respond_to(klass, rb_intern("subclass_initialize")))
00128         rb_funcall(klass, rb_intern("subclass_initialize"), 0);
00129 
00130     wrappers.insert(std::make_pair(&type, std::make_pair(false, klass)));
00131     return klass;
00132 }
00133 
00134 /**********************************************
00135  * Typelib::Type
00136  */
00137 
00138 /* @overload type.to_csv([basename [, separator]])
00139  *
00140  * Returns a one-line representation of this type, using +separator+ 
00141  * to separate each fields. If +basename+ is given, use it as a 
00142  * 'variable name'. For instance, calling this method on an array
00143  * with a basename of 'array' will return
00144  *  
00145  *   array[0] array[1]
00146  *
00147  * without basename, it would be 
00148  *
00149  *   [0] [1]
00150  *
00151  */
00152 static VALUE type_to_csv(int argc, VALUE* argv, VALUE rbself)
00153 {
00154     VALUE basename = Qnil;
00155     VALUE separator = Qnil;
00156     rb_scan_args(argc, argv, "02", &basename, &separator);
00157 
00158     std::string bname = "", sep = " ";
00159     if (!NIL_P(basename)) bname = StringValuePtr(basename);
00160     if (!NIL_P(separator)) sep = StringValuePtr(separator);
00161 
00162     Type const& self(rb2cxx::object<Type>(rbself));
00163     std::ostringstream stream;
00164     stream << csv_header(self, bname, sep);
00165     std::string str = stream.str();
00166     return rb_str_new(str.c_str(), str.length());
00167 }
00168 
00169 /* @overload t.basename
00170  *
00171  * Returns the type name of the receiver with the namespace part
00172  * removed
00173  *
00174  * @return [String]
00175  */
00176 static VALUE typelib_do_basename(VALUE mod, VALUE name)
00177 {
00178     std::string result = Typelib::getTypename(StringValuePtr(name));
00179     return rb_str_new(result.c_str(), result.length());
00180 }
00181 
00182 /* Internal helper method for Type#namespace */
00183 static VALUE typelib_do_namespace(VALUE mod, VALUE name)
00184 {
00185     std::string result = Typelib::getNamespace(StringValuePtr(name));
00186     return rb_str_new(result.c_str(), result.length());
00187 }
00188 
00189 /* @overload split_typename
00190  *
00191  * Splits the typename of self into its components
00192  * 
00193  * @return [Array<String>]
00194  */
00195 static VALUE typelib_do_split_name(VALUE mod, VALUE name)
00196 {
00197     std::list<std::string> splitted = Typelib::splitTypename(StringValuePtr(name));
00198     VALUE result = rb_ary_new();
00199     for (std::list<std::string>::const_iterator it = splitted.begin(); it != splitted.end(); ++it)
00200         rb_ary_push(result, rb_str_new(it->c_str(), it->length()));
00201     return result;
00202 }
00203 
00204 
00205 /* @overload t1 == t2
00206  *
00207  * Returns true if +t1+ and +t2+ are the same type definition.
00208  *
00209  * @return [Boolean]
00210  */
00211 static VALUE type_equal_operator(VALUE rbself, VALUE rbwith)
00212 { 
00213     if (rbself == rbwith)
00214         return Qtrue;
00215     if (!rb_obj_is_kind_of(rbwith, rb_cClass))
00216         return Qfalse;
00217     if ((rbwith == cType) || !RTEST(rb_funcall(rbwith, rb_intern("<"), 1, cType)))
00218         return Qfalse;
00219 
00220     Type const& self(rb2cxx::object<Type>(rbself));
00221     Type const& with(rb2cxx::object<Type>(rbwith));
00222     bool result = (self == with) || self.isSame(with);
00223     return result ? Qtrue : Qfalse;
00224 }
00225 
00226 /* @overload type.size
00227  *
00228  * Returns the size in bytes of instances of +type+
00229  */
00230 static VALUE type_size(VALUE self)
00231 {
00232     Type const& type(rb2cxx::object<Type>(self));
00233     return INT2FIX(type.getSize());
00234 }
00235 
00236 /* Returns the set of Type subclasses that represent the types needed to build
00237  * +type+.
00238  */
00239 static VALUE type_dependencies(VALUE self)
00240 {
00241     Type const& type(rb2cxx::object<Type>(self));
00242 
00243     typedef std::set<Type const*> TypeSet;
00244     TypeSet dependencies = type.dependsOn();
00245     VALUE registry = type_get_registry(self);
00246 
00247     VALUE result = rb_ary_new();
00248     for (TypeSet::const_iterator it = dependencies.begin(); it != dependencies.end(); ++it)
00249         rb_ary_push(result, cxx2rb::type_wrap(**it, registry));
00250     return result;
00251 }
00252 
00253 /* @overload type.casts_to?(other_type) => true or false
00254  *
00255  * Returns true if a value that is described by +type+ can be manipulated using
00256  * +other_type+. This is a weak form of equality
00257  */
00258 static VALUE type_can_cast_to(VALUE self, VALUE to)
00259 {
00260     Type const& from_type(rb2cxx::object<Type>(self));
00261     Type const& to_type(rb2cxx::object<Type>(to));
00262     return from_type.canCastTo(to_type) ? Qtrue : Qfalse;
00263 }
00264 
00265 /*
00266  *  type.do_memory_layout(VALUE accept_pointers, VALUE accept_opaques, VALUE merge_skip_copy, VALUE remove_trailing_skips) => [operations]
00267  *
00268  * Returns a representation of the MemoryLayout for this type. If
00269  * +with_pointers+ is true, then pointers will be included in the layout.
00270  * Otherwise, an exception is raised if pointers are part of the type
00271  */
00272 static VALUE type_memory_layout(VALUE self, VALUE pointers, VALUE opaques, VALUE merge, VALUE remove_trailing_skips)
00273 {
00274     Type const& type(rb2cxx::object<Type>(self));
00275     VALUE registry = type_get_registry(self);
00276 
00277     VALUE result = rb_ary_new();
00278 
00279     VALUE rb_memcpy = ID2SYM(rb_intern("FLAG_MEMCPY"));
00280     VALUE rb_skip = ID2SYM(rb_intern("FLAG_SKIP"));
00281     VALUE rb_array = ID2SYM(rb_intern("FLAG_ARRAY"));
00282     VALUE rb_end = ID2SYM(rb_intern("FLAG_END"));
00283     VALUE rb_container = ID2SYM(rb_intern("FLAG_CONTAINER"));
00284 
00285     try {
00286         MemoryLayout layout = Typelib::layout_of(type, RTEST(pointers), RTEST(opaques), RTEST(merge), RTEST(remove_trailing_skips));
00287 
00288         // Now, convert into something representable in Ruby
00289         for (MemoryLayout::const_iterator it = layout.begin(); it != layout.end(); ++it)
00290         {
00291             switch(*it)
00292             {
00293                 case MemLayout::FLAG_MEMCPY:
00294                     rb_ary_push(result, rb_memcpy);
00295                     rb_ary_push(result, LONG2NUM(*(++it)));
00296                     break;
00297                 case MemLayout::FLAG_SKIP:
00298                     rb_ary_push(result, rb_skip);
00299                     rb_ary_push(result, LONG2NUM(*(++it)));
00300                     break;
00301                 case MemLayout::FLAG_ARRAY:
00302                     rb_ary_push(result, rb_array);
00303                     rb_ary_push(result, LONG2NUM(*(++it)));
00304                     break;
00305                 case MemLayout::FLAG_END:
00306                     rb_ary_push(result, rb_end);
00307                     break;
00308                 case MemLayout::FLAG_CONTAINER:
00309                     rb_ary_push(result, rb_container);
00310                     rb_ary_push(result, cxx2rb::type_wrap(*reinterpret_cast<Container*>(*(++it)), registry));
00311                     break;
00312                 default:
00313                     rb_raise(rb_eArgError, "error encountered while parsing memory layout");
00314             }
00315         }
00316 
00317     } catch(std::exception const& e) {
00318         rb_raise(rb_eArgError, "%s", e.what());
00319     }
00320 
00321     return result;
00322 }
00323 
00324 /* PODs are assignable, pointers are dereferenced */
00325 static VALUE type_is_assignable(Type const& type)
00326 {
00327     switch(type.getCategory())
00328     {
00329     case Type::Numeric:
00330         return INT2FIX(1);
00331     case Type::Pointer:
00332         return type_is_assignable( dynamic_cast<Pointer const&>(type).getIndirection());
00333     case Type::Enum:
00334         return INT2FIX(1);
00335     default:
00336         return INT2FIX(0);
00337     }
00338     // never reached
00339 }
00340 
00341 VALUE typelib_ruby::type_get_registry(VALUE self)
00342 {
00343     return rb_iv_get(self, "@registry");
00344 }
00345 
00346 
00347 /***********************************************************************************
00348  *
00349  * Wrapping of the Value class
00350  *
00351  */
00352 
00353 static void value_delete(void* self) { delete reinterpret_cast<Value*>(self); }
00354 
00355 static VALUE value_alloc(VALUE klass)
00356 { return Data_Wrap_Struct(klass, 0, value_delete, new Value); }
00357 
00361 static
00362 VALUE value_create_empty(VALUE klass)
00363 {
00364     Type const& t(rb2cxx::object<Type>(klass));
00365     VALUE value = Data_Wrap_Struct(klass, 0, value_delete, new Value(NULL, t));
00366     rb_iv_set(value, "@parent", Qnil);
00367     return value;
00368 }
00369 
00370 static
00371 void value_call_typelib_initialize(VALUE obj)
00372 {
00373     rb_iv_set(obj, "@__typelib_invalidated", Qfalse);
00374     rb_iv_set(obj, "@parent", Qnil);
00375     rb_funcall(obj, rb_intern("typelib_initialize"), 0);
00376 }
00377 
00378 /* @overload from_memory_zone(ptr)
00379  *
00380  * @param [Typelib::MemoryZone] ptr
00381  * @return [Typelib::Type]
00382  *
00383  * Allocates a new Typelib object that uses a given MemoryZone object
00384  */
00385 static
00386 VALUE value_from_memory_zone(VALUE klass, VALUE ptr)
00387 {
00388     VALUE result = value_create_empty(klass);
00389     Value& value  = rb2cxx::object<Value>(result);
00390     
00391     // Protect the memory zone against GC until we don't need it anymore
00392     rb_iv_set(result, "@ptr", ptr);
00393     value = Value(memory_cptr(ptr), value.getType());
00394 #   ifdef VERBOSE
00395     fprintf(stderr, "object %llu wraps memory zone %p\n", NUM2ULL(rb_obj_id(result)), value.getData());
00396 #   endif
00397     value_call_typelib_initialize(result);
00398     return result;
00399 }
00400 
00401 /* @overload new
00402  *
00403  * @return [Typelib::Type]
00404  *
00405  * Allocates a new Typelib object that has a freshly initialized buffer inside
00406  */
00407 static
00408 VALUE value_new(VALUE klass)
00409 {
00410     Type const& type(rb2cxx::object<Type>(klass));
00411 #   ifdef VERBOSE
00412     fprintf(stderr, "allocating new value of type %s\n", type.getName().c_str());
00413 #   endif
00414     VALUE buffer = memory_allocate(type.getSize());
00415     memory_init(buffer, klass);
00416 
00417     return value_from_memory_zone(klass, buffer);
00418 }
00419 
00420 static
00421 VALUE value_do_from_buffer(VALUE rbself, VALUE string, VALUE pointers, VALUE opaques, VALUE merge, VALUE remove_trailing_skips)
00422 {
00423     Value value  = rb2cxx::object<Value>(rbself);
00424 
00425     MemoryLayout layout = Typelib::layout_of(value.getType(),
00426             RTEST(pointers), RTEST(opaques), RTEST(merge), RTEST(remove_trailing_skips));
00427 
00428     char* ruby_buffer = StringValuePtr(string);
00429     vector<uint8_t> cxx_buffer(ruby_buffer, ruby_buffer + RSTRING_LEN(string));
00430     try { Typelib::load(value, cxx_buffer, layout); }
00431     catch(std::exception const& e)
00432     { rb_raise(rb_eArgError, "%s", e.what()); }
00433     return rbself;
00434 }
00435 
00436 /* @overload from_address(address)
00437  *
00438  * Creates a value that wraps a given memory address
00439  *
00440  * @param [Integer] address
00441  * @return [Typelib::Type]
00442  */
00443 static
00444 VALUE value_from_address(VALUE klass, VALUE address)
00445 {
00446     VALUE result = value_create_empty(klass);
00447     Value& value  = rb2cxx::object<Value>(result);
00448     value = Value(reinterpret_cast<void*>(NUM2ULL(address)), value.getType());
00449     rb_iv_set(result, "@ptr", memory_wrap(value.getData(), false, NULL));
00450     value_call_typelib_initialize(result);
00451     return result;
00452 }
00453 
00454 /* @overload address
00455  *
00456  * @return [Integer] returns the address of the memory zone this value wraps
00457  */
00458 static
00459 VALUE value_address(VALUE self)
00460 {
00461     Value value = rb2cxx::object<Value>(self);
00462     return LONG2NUM((long)value.getData());
00463 }
00464 
00465 /* @overload endian_swap
00466  *
00467  * Creates a new value with an endianness opposite of the one of self
00468  *
00469  * @return [Typelib::Type] a new value whose endianness has been swapped
00470  * @see endian_swap!
00471  */
00472 static
00473 VALUE value_endian_swap(VALUE self)
00474 {
00475     Value& value = rb2cxx::object<Value>(self);
00476     CompileEndianSwapVisitor compiled;
00477     compiled.apply(value.getType());
00478 
00479     VALUE registry = value_get_registry(self);
00480     VALUE result   = value_allocate(value.getType(), registry);
00481     compiled.swap(value, rb2cxx::object<Value>(result));
00482     return result;
00483 }
00484 
00485 /* @overload endian_swap!
00486  *
00487  * Swaps the endianness of self
00488  *
00489  * @return [Typelib::Type] self
00490  * @see endian_swap
00491  */
00492 static
00493 VALUE value_endian_swap_b(VALUE self, VALUE rb_compile)
00494 {
00495     Value& value = rb2cxx::object<Value>(self);
00496     endian_swap(value);
00497     return self;
00498 }
00499 
00500 static
00501 VALUE value_do_cast(VALUE self, VALUE target_type)
00502 {
00503     Value& value = rb2cxx::object<Value>(self);
00504     Type const& to_type(rb2cxx::object<Type>(target_type));
00505 
00506     if (value.getType() == to_type)
00507         return self;
00508 
00509     VALUE registry = rb_iv_get(target_type, "@registry");
00510     Value casted(value.getData(), to_type);
00511 #   ifdef VERBOSE
00512     fprintf(stderr, "wrapping casted value\n");
00513 #   endif
00514 
00515     return cxx2rb::value_wrap(casted, registry, self);
00516 }
00517 
00518 static
00519 VALUE value_invalidate(VALUE self)
00520 {
00521     if (NIL_P(rb_iv_get(self, "@parent")))
00522         rb_raise(rb_eArgError, "cannot invalidate a toplevel value");
00523 
00524     Value& value = rb2cxx::object<Value>(self);
00525 #ifdef VERBOSE
00526     fprintf(stderr, "invalidating %llu, ptr=%p\n", NUM2ULL(rb_obj_id(self)), value.getData());
00527 #endif
00528     value = Value(0, value.getType());
00529     rb_funcall(rb_iv_get(self, "@ptr"), rb_intern("invalidate"), 0);
00530     return Qnil;
00531 }
00532 
00533 static
00534 VALUE value_do_byte_array(VALUE self, VALUE pointers, VALUE opaques, VALUE merge, VALUE remove_trailing_skips)
00535 {
00536     Value& value = rb2cxx::object<Value>(self);
00537     MemoryLayout layout = Typelib::layout_of(value.getType(), RTEST(pointers), RTEST(opaques), RTEST(merge), RTEST(remove_trailing_skips));
00538 
00539     vector<uint8_t> buffer;
00540     Typelib::dump(value, buffer, layout);
00541     return rb_str_new(reinterpret_cast<char*>(&buffer[0]), buffer.size());
00542 }
00543 
00544 /* call-seq:
00545  *  obj.marshalling_size => integer
00546  *
00547  * Returns the size of this value once marshalled by Typelib, i.e. the size of
00548  * the byte array returned by #to_byte_array
00549  */
00550 static
00551 VALUE value_marshalling_size(VALUE self)
00552 {
00553     Value& value = rb2cxx::object<Value>(self);
00554     try { return INT2NUM(Typelib::getDumpSize(value)); }
00555     catch(Typelib::NoLayout)
00556     { return Qnil; }
00557 }
00558 
00559 VALUE value_memory_eql_p(VALUE rbself, VALUE rbwith)
00560 {
00561     Value& self = rb2cxx::object<Value>(rbself);
00562     Value& with = rb2cxx::object<Value>(rbwith);
00563         
00564     if (self.getData() == with.getData())
00565         return Qtrue;
00566     
00567     // Type#== checks for type equality before calling memory_equal?
00568     Type const& type = self.getType();
00569     return memcmp(self.getData(), with.getData(), type.getSize()) == 0 ? Qtrue : Qfalse;
00570 }
00571 
00572 VALUE typelib_ruby::value_get_registry(VALUE self)
00573 {
00574     VALUE type = rb_funcall(self, rb_intern("class"), 0);
00575     return rb_iv_get(type, "@registry");
00576 }
00577 
00585 static VALUE value_to_csv(int argc, VALUE* argv, VALUE self)
00586 {
00587     VALUE separator = Qnil;
00588     rb_scan_args(argc, argv, "01", &separator);
00589 
00590     Value const& value(rb2cxx::object<Value>(self));
00591     std::string sep = " ";
00592     if (!NIL_P(separator)) sep = StringValuePtr(separator);
00593 
00594     std::ostringstream stream;
00595     stream << csv(value.getType(), value.getData(), sep);
00596     std::string str = stream.str();
00597     return rb_str_new(str.c_str(), str.length());
00598 }
00599 
00600 /* Initializes the memory to 0 */
00601 static VALUE value_zero(VALUE self)
00602 {
00603     Value const& value(rb2cxx::object<Value>(self));
00604     Typelib::zero(value);
00605     return self;
00606 }
00607 
00608 static VALUE typelib_do_copy(VALUE, VALUE to, VALUE from)
00609 {
00610     Value v_from = rb2cxx::object<Value>(from);
00611     Value v_to   = rb2cxx::object<Value>(to);
00612 
00613     if (v_from.getType() != v_to.getType())
00614     {
00615         // Do a deep check for type equality
00616         if (!v_from.getType().canCastTo(v_to.getType()))
00617             rb_raise(rb_eArgError, "cannot copy: types are not compatible");
00618     }
00619     Typelib::copy(v_to.getData(), v_from.getData(), v_from.getType());
00620     return to;
00621 }
00622 
00623 /* call-seq:
00624  *  Typelib.compare(to, from) => true or false
00625  *
00626  * Proper comparison of two values. +to+ and +from+'s types do not have to be of
00627  * the same registries, as long as the types can be cast'ed into each other.
00628  */
00629 static VALUE typelib_compare(VALUE, VALUE to, VALUE from)
00630 {
00631     Value v_from = rb2cxx::object<Value>(from);
00632     Value v_to   = rb2cxx::object<Value>(to);
00633 
00634     if (v_from.getType() != v_to.getType())
00635     {
00636         // Do a deep check for type equality
00637         if (!v_from.getType().canCastTo(v_to.getType()))
00638             rb_raise(rb_eArgError, "cannot compare: %s and %s are not compatible types",
00639                     v_from.getType().getName().c_str(),
00640                     v_to.getType().getName().c_str());
00641     }
00642     try {
00643         bool result = Typelib::compare(v_to.getData(), v_from.getData(), v_from.getType());
00644         return result ? Qtrue : Qfalse;
00645     } catch(std::exception const& e) {
00646         rb_raise(rb_eArgError, "%s", e.what());
00647     }
00648 }
00649 
00650 
00651 void typelib_ruby::Typelib_init_values()
00652 {
00653     VALUE mTypelib  = rb_define_module("Typelib");
00654     rb_define_singleton_method(mTypelib, "do_copy", RUBY_METHOD_FUNC(typelib_do_copy), 2);
00655     rb_define_singleton_method(mTypelib, "compare", RUBY_METHOD_FUNC(typelib_compare), 2);
00656 
00657     cType     = rb_define_class_under(mTypelib, "Type", rb_cObject);
00658     rb_define_alloc_func(cType, value_alloc);
00659     rb_define_singleton_method(cType, "==",            RUBY_METHOD_FUNC(type_equal_operator), 1);
00660     rb_define_singleton_method(cType, "size",          RUBY_METHOD_FUNC(&type_size), 0);
00661     rb_define_singleton_method(cType, "do_memory_layout", RUBY_METHOD_FUNC(&type_memory_layout), 4);
00662     rb_define_singleton_method(cType, "do_dependencies",  RUBY_METHOD_FUNC(&type_dependencies), 0);
00663     rb_define_singleton_method(cType, "casts_to?",     RUBY_METHOD_FUNC(&type_can_cast_to), 1);
00664     rb_define_singleton_method(cType, "value_new", RUBY_METHOD_FUNC(&value_new), 0);
00665     rb_define_singleton_method(cType, "from_memory_zone", RUBY_METHOD_FUNC(&value_from_memory_zone), 1);
00666     rb_define_singleton_method(cType, "from_address", RUBY_METHOD_FUNC(&value_from_address), 1);
00667 
00668     rb_define_method(cType, "do_from_buffer", RUBY_METHOD_FUNC(&value_do_from_buffer), 5);
00669     rb_define_method(cType, "zero!",      RUBY_METHOD_FUNC(&value_zero), 0);
00670     rb_define_method(cType, "memory_eql?",      RUBY_METHOD_FUNC(&value_memory_eql_p), 1);
00671     rb_define_method(cType, "endian_swap",      RUBY_METHOD_FUNC(&value_endian_swap), 0);
00672     rb_define_method(cType, "endian_swap!",      RUBY_METHOD_FUNC(&value_endian_swap_b), 0);
00673     rb_define_method(cType, "zone_address", RUBY_METHOD_FUNC(&value_address), 0);
00674     rb_define_method(cType, "do_cast", RUBY_METHOD_FUNC(&value_do_cast), 1);
00675     rb_define_method(cType, "do_invalidate", RUBY_METHOD_FUNC(&value_invalidate), 0);
00676 
00677     rb_define_singleton_method(mTypelib, "do_basename",  RUBY_METHOD_FUNC(typelib_do_basename), 1);
00678     rb_define_singleton_method(mTypelib, "do_namespace", RUBY_METHOD_FUNC(typelib_do_namespace), 1);
00679     rb_define_singleton_method(mTypelib, "split_typename", RUBY_METHOD_FUNC(typelib_do_split_name), 1);
00680 
00681     rb_define_singleton_method(cType, "to_csv", RUBY_METHOD_FUNC(type_to_csv), -1);
00682     rb_define_method(cType, "to_csv", RUBY_METHOD_FUNC(value_to_csv), -1);
00683     rb_define_method(cType, "do_byte_array", RUBY_METHOD_FUNC(value_do_byte_array), 4);
00684     rb_define_method(cType, "marshalling_size", RUBY_METHOD_FUNC(value_marshalling_size), 0);
00685 
00686     Typelib_init_specialized_types();
00687 }
00688 


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Sat Jun 8 2019 18:49:22