$search
00001 #include "typelib.hh" 00002 #include <iostream> 00003 #include <typelib/value_ops.hh> 00004 00005 using namespace Typelib; 00006 using namespace typelib_ruby; 00007 00008 /********** 00009 * Define typelib_(to|from)_ruby 00010 */ 00011 00012 /* This visitor takes a Value class and a field name, 00013 * and returns the VALUE object which corresponds to 00014 * the field, or returns nil 00015 */ 00016 bool RubyGetter::visit_ (int8_t & value) { m_value = INT2FIX(value); return false; } 00017 bool RubyGetter::visit_ (uint8_t & value) { m_value = INT2FIX(value); return false; } 00018 bool RubyGetter::visit_ (int16_t & value) { m_value = INT2FIX(value); return false; } 00019 bool RubyGetter::visit_ (uint16_t& value) { m_value = INT2FIX(value); return false; } 00020 bool RubyGetter::visit_ (int32_t & value) { m_value = INT2NUM(value); return false; } 00021 bool RubyGetter::visit_ (uint32_t& value) { m_value = INT2NUM(value); return false; } 00022 bool RubyGetter::visit_ (int64_t & value) { m_value = LL2NUM(value); return false; } 00023 bool RubyGetter::visit_ (uint64_t& value) { m_value = ULL2NUM(value); return false; } 00024 bool RubyGetter::visit_ (float & value) { m_value = rb_float_new(value); return false; } 00025 bool RubyGetter::visit_ (double & value) { m_value = rb_float_new(value); return false; } 00026 00027 bool RubyGetter::visit_(Value const& v, Pointer const& p) 00028 { 00029 # ifdef VERBOSE 00030 fprintf(stderr, "%p: wrapping from RubyGetter::visit_(pointer)\n", v.getData()); 00031 # endif 00032 m_value = cxx2rb::value_wrap(v, m_registry, m_parent); 00033 return false; 00034 } 00035 bool RubyGetter::visit_(Value const& v, Array const& a) 00036 { 00037 # ifdef VERBOSE 00038 fprintf(stderr, "%p: wrapping from RubyGetter::visit_(array)\n", v.getData()); 00039 # endif 00040 m_value = cxx2rb::value_wrap(v, m_registry, m_parent); 00041 return false; 00042 } 00043 bool RubyGetter::visit_(Value const& v, Compound const& c) 00044 { 00045 # ifdef VERBOSE 00046 fprintf(stderr, "%p: wrapping from RubyGetter::visit_(compound)\n", v.getData()); 00047 # endif 00048 m_value = cxx2rb::value_wrap(v, m_registry, m_parent); 00049 return false; 00050 } 00051 bool RubyGetter::visit_(Value const& v, OpaqueType const& c) 00052 { 00053 # ifdef VERBOSE 00054 fprintf(stderr, "%p: wrapping from RubyGetter::visit_(opaque)\n", v.getData()); 00055 # endif 00056 m_value = cxx2rb::value_wrap(v, m_registry, m_parent); 00057 return false; 00058 } 00059 bool RubyGetter::visit_(Value const& v, Container const& c) 00060 { 00061 # ifdef VERBOSE 00062 fprintf(stderr, "%p: wrapping from RubyGetter::visit_(container)\n", v.getData()); 00063 # endif 00064 m_value = cxx2rb::value_wrap(v, m_registry, m_parent); 00065 return false; 00066 } 00067 bool RubyGetter::visit_(Enum::integral_type& v, Enum const& e) 00068 { 00069 m_value = cxx2rb::enum_symbol(v, e); 00070 return false; 00071 } 00072 00073 RubyGetter::RubyGetter() : ValueVisitor(false) {} 00074 RubyGetter::~RubyGetter() { m_value = Qnil; m_registry = Qnil; } 00075 00076 VALUE RubyGetter::apply(Typelib::Value value, VALUE registry, VALUE parent) 00077 { 00078 m_registry = registry; 00079 m_value = Qnil; 00080 m_parent = parent; 00081 00082 ValueVisitor::apply(value); 00083 return m_value; 00084 } 00085 00086 bool RubySetter::visit_ (int8_t & value) { value = NUM2INT(m_value); return false; } 00087 bool RubySetter::visit_ (uint8_t & value) { value = NUM2INT(m_value); return false; } 00088 bool RubySetter::visit_ (int16_t & value) { value = NUM2INT(m_value); return false; } 00089 bool RubySetter::visit_ (uint16_t& value) { value = NUM2UINT(m_value); return false; } 00090 bool RubySetter::visit_ (int32_t & value) { value = NUM2INT(m_value); return false; } 00091 bool RubySetter::visit_ (uint32_t& value) { value = NUM2UINT(m_value); return false; } 00092 bool RubySetter::visit_ (int64_t & value) { value = NUM2LL(m_value); return false; } 00093 bool RubySetter::visit_ (uint64_t& value) { value = NUM2LL(m_value); return false; } 00094 bool RubySetter::visit_ (float & value) { value = NUM2DBL(m_value); return false; } 00095 bool RubySetter::visit_ (double & value) { value = NUM2DBL(m_value); return false; } 00096 00097 bool RubySetter::visit_(Value const& v, Array const& a) 00098 { 00099 if (a.getIndirection().getName() == "/char") 00100 { 00101 char* value = StringValuePtr(m_value); 00102 size_t length = strlen(value); 00103 if (length < a.getDimension()) 00104 { 00105 memcpy(v.getData(), value, length + 1); 00106 return false; 00107 } 00108 throw UnsupportedType(v.getType(), "string too long"); 00109 } 00110 throw UnsupportedType(v.getType(), "not a string"); 00111 } 00112 bool RubySetter::visit_(Value const& v, Pointer const& c) 00113 { 00114 throw UnsupportedType(v.getType(), "no conversion to pointers"); 00115 } 00116 bool RubySetter::visit_(Value const& v, Compound const& c) 00117 { 00118 throw UnsupportedType(v.getType(), "no conversion to compound"); 00119 } 00120 bool RubySetter::visit_(Value const& v, OpaqueType const& c) 00121 { 00122 throw UnsupportedType(v.getType(), "no conversion to opaque types"); 00123 } 00124 bool RubySetter::visit_(Value const& v, Container const& c) 00125 { 00126 throw UnsupportedType(v.getType(), "no conversion to containers"); 00127 } 00128 bool RubySetter::visit_(Enum::integral_type& v, Enum const& e) 00129 { 00130 v = rb2cxx::enum_value(m_value, e); 00131 return false; 00132 } 00133 00134 RubySetter::RubySetter() : ValueVisitor(false) {} 00135 RubySetter::~RubySetter() { m_value = Qnil; } 00136 00137 VALUE RubySetter::apply(Value value, VALUE new_value) 00138 { 00139 m_value = new_value; 00140 ValueVisitor::apply(value); 00141 return new_value; 00142 } 00143 00144 /* 00145 * Convertion function between Ruby and Typelib 00146 */ 00147 00148 /* Converts a Typelib::Value to Ruby's VALUE */ 00149 VALUE typelib_to_ruby(Value v, VALUE registry, VALUE parent) 00150 { 00151 if (! v.getData()) 00152 return Qnil; 00153 00154 RubyGetter getter; 00155 return getter.apply(v, registry, parent); 00156 } 00157 00158 /* Returns the Value object wrapped into +value+ */ 00159 Value typelib_get(VALUE value) 00160 { 00161 void* object = 0; 00162 Data_Get_Struct(value, void, object); 00163 return *reinterpret_cast<Value*>(object); 00164 } 00165 00166 /* Tries to initialize +value+ to +new_value+ using the type in +value+ */ 00167 VALUE typelib_from_ruby(Value dst, VALUE new_value) 00168 { 00169 // Special case: new_value is actually a Typelib wrapper of the right type 00170 if (rb_obj_is_kind_of(new_value, cType)) 00171 { 00172 Value& src = rb2cxx::object<Value>(new_value); 00173 Type const& dst_t = dst.getType(); 00174 Type const& src_t = src.getType(); 00175 if (dst_t == src_t) 00176 Typelib::copy(dst, src); 00177 else 00178 { 00179 rb_raise(rb_eArgError, "wrong type in assignment: %s = %s", dst_t.getName().c_str(), src_t.getName().c_str()); 00180 } 00181 return new_value; 00182 } 00183 00184 std::string type_name; 00185 std::string reason; 00186 try { 00187 RubySetter setter; 00188 return setter.apply(dst, new_value); 00189 } catch(UnsupportedType e) { 00190 // Avoid calling rb_raise in exception context 00191 type_name = e.type.getName(); 00192 reason = e.reason; 00193 } 00194 00195 if (reason.length() == 0) 00196 rb_raise(rb_eTypeError, "cannot convert to '%s'", type_name.c_str()); 00197 else 00198 rb_raise(rb_eTypeError, "cannot convert to '%s' (%s)", type_name.c_str(), reason.c_str()); 00199 } 00200