/*************************************************************************** * rubyvariant.h * This file is part of the KDE project * copyright (C)2005 by Cyrille Berger (cberger@cberger.net) * copyright (C)2006 by Sebastian Sauer (mail@dipe.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * You should have received a copy of the GNU Library General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. ***************************************************************************/ #ifndef KROSS_RUBYVARIANT_H #define KROSS_RUBYVARIANT_H #define HAVE_STRLCAT_PROTO 1 #define HAVE_STRLCPY_PROTO 1 #include "config.h" #include #ifndef HAVE_RUBY_1_9 #include #else // HAVE_RUBY_1_9 #include #define STR2CSTR(x) StringValuePtr(x) #endif // HAVE_RUBY_1_9 //#include #include "rubyconfig.h" #include #include #include #include #include #include #include #include namespace Kross { /** * The RubyType helper classes used to cast between TQVariant * and VALUE values. * * Following TQVariant::Type's are implemented; * \li TQVariant::Invalid * \li TQVariant::Int * \li TQVariant::UInt * \li TQVariant::Double * \li TQVariant::Bool * \li TQVariant::LongLong * \li TQVariant::ULongLong * \li TQVariant::ByteArray * \li TQVariant::String * \li TQVariant::StringList * \li TQVariant::Size * \li TQVariant::SizeF * \li TQVariant::Point * \li TQVariant::PointF * \li TQVariant::Rect * \li TQVariant::RectF * \li TQVariant::Url * \li TQVariant::List * \li TQVariant::Map * * Following TQVariant::Type's are unimplemented yet (do we need them anyways?); * \li TQVariant::BitArray * \li TQVariant::Date * \li TQVariant::Time * \li TQVariant::DateTime * \li TQVariant::Bitmap * \li TQVariant::Brush * \li TQVariant::Char * \li TQVariant::Color * \li TQVariant::Cursor * \li TQVariant::Font * \li TQVariant::Icon * \li TQVariant::Image * \li TQVariant::KeySequence * \li TQVariant::Line * \li TQVariant::LineF * \li TQVariant::Locale * \li TQVariant::Palette * \li TQVariant::Pen * \li TQVariant::Pixmap * \li TQVariant::PointArray * \li TQVariant::Polygon * \li TQVariant::RegExp * \li TQVariant::Region * \li TQVariant::SizePolicy * \li TQVariant::TextFormat * \li TQVariant::TextLength */ template struct RubyType { // template-specialisations need to implement following both static // functions to translate between TQVariant and Ruby's VALUE values. //inline static RBTYPE toVALUE(const VARIANTTYPE&) { return Py::None(); } //inline static TQVARIANTTYPE toVariant(const VARIANTTYPE&) { return TQVariant(); } }; /// \internal template<> struct RubyType { static VALUE toVALUE(const TQVariant& v); static TQVariant toVariant(VALUE value); }; /// \internal template<> struct RubyType { inline static VALUE toVALUE(int i) { return INT2FIX(i); } inline static int toVariant(VALUE value) { switch( TYPE(value) ) { case T_FIXNUM: return FIX2INT(value); case T_BIGNUM: return rb_big2int(value); case T_FLOAT: #ifdef HAVE_RUBY_1_9 return (int)(RFLOAT_VALUE(value)); #else return (int)(RFLOAT(value)->value); #endif default: break; } rb_raise(rb_eTypeError, "Integer must be a fixed number"); return 0; } }; /// \internal template<> struct RubyType { inline static VALUE toVALUE(uint i) { return UINT2NUM(i); } inline static uint toVariant(VALUE value) { switch( TYPE(value) ) { case T_FIXNUM: return FIX2UINT(value); case T_BIGNUM: return rb_big2uint(value); case T_FLOAT: #ifdef HAVE_RUBY_1_9 return (uint)(RFLOAT_VALUE(value)); #else return (uint)(RFLOAT(value)->value); #endif default: break; } rb_raise(rb_eTypeError, "Unsigned integer must be a fixed number"); return 0; } }; /// \internal template<> struct RubyType { inline static VALUE toVALUE(double d) { return rb_float_new(d); } inline static double toVariant(VALUE value) { return NUM2DBL(value); } }; /// \internal template<> struct RubyType { inline static VALUE toVALUE(bool b) { return b ? TRUE : FALSE; } inline static bool toVariant(VALUE value) { switch( TYPE(value) ) { case T_TRUE: return true; case T_FALSE: return false; default: { rb_raise(rb_eTypeError, "Boolean value expected"); return false; } break; } } }; /// \internal template<> struct RubyType { inline static VALUE toVALUE(TQ_LLONG l) { return /*INT2NUM*/ LONG2NUM((long)l); } inline static TQ_LLONG toVariant(VALUE value) { return NUM2LONG(value); } }; /// \internal template<> struct RubyType { inline static VALUE toVALUE(TQ_ULLONG l) { return UINT2NUM((unsigned long)l); } inline static TQ_ULLONG toVariant(VALUE value) { return NUM2UINT(value); } }; /// \internal template<> struct RubyType { inline static VALUE toVALUE(const TQByteArray& ba) { return rb_str_new(ba.data(), ba.size()); } inline static TQByteArray toVariant(VALUE value) { if( TYPE(value) != T_STRING ) { rb_raise(rb_eTypeError, "TQByteArray must be a string"); //return STR2CSTR( rb_inspect(value) ); return TQCString(""); } #ifdef HAVE_RUBY_1_9 long length = LONG2NUM( RSTRING_LEN(value) ); #else long length = LONG2NUM( RSTRING(value)->len ); #endif if( length < 0 ) return TQCString(""); #ifdef HAVE_RUBY_1_9 return TQCString(RSTRING_PTR(value), RSTRING_LEN(value)); #else // HAVE_RUBY_1_9 char* ca = rb_str2cstr(value, &length); return TQCString(ca, length); #endif // HAVE_RUBY_1_9 } }; /// \internal template<> struct RubyType { inline static VALUE toVALUE(const TQString& s) { return s.isNull() ? rb_str_new2("") : rb_str_new2(s.latin1()); } inline static TQString toVariant(VALUE value) { if( TYPE(value) != T_STRING ) { rb_raise(rb_eTypeError, "TQString must be a string"); return TQString(); } return STR2CSTR(value); } }; /// \internal template<> struct RubyType { inline static VALUE toVALUE(const TQSize& s) { VALUE l = rb_ary_new(); rb_ary_push(l, RubyType::toVALUE(s.width())); rb_ary_push(l, RubyType::toVALUE(s.height())); return l; } inline static TQSize toVariant(VALUE value) { #ifdef HAVE_RUBY_1_9 if( TYPE(value) != T_ARRAY || RARRAY_LEN(value) != 2 ) { #else if( TYPE(value) != T_ARRAY || RARRAY(value)->len != 2 ) { #endif rb_raise(rb_eTypeError, "TQSize must be an array with 2 elements"); return TQSize(); } return TQSize( RubyType::toVariant( rb_ary_entry(value,0) ), RubyType::toVariant( rb_ary_entry(value,1) ) ); } }; #if 0 /// \internal template<> struct RubyType { inline static VALUE toVALUE(const TQSizeF& s) { VALUE l = rb_ary_new(); rb_ary_push(l, RubyType::toVALUE(s.width())); rb_ary_push(l, RubyType::toVALUE(s.height())); return l; } inline static TQSizeF toVariant(VALUE value) { #ifdef HAVE_RUBY_1_9 if( TYPE(value) != T_ARRAY || RARRAY_LEN(value) != 2 ) { #else if( TYPE(value) != T_ARRAY || RARRAY(value)->len != 2 ) { #endif rb_raise(rb_eTypeError, "TQSizeF must be an array with 2 elements"); return TQSizeF(); } return TQSizeF( RubyType::toVariant( rb_ary_entry(value,0) ), RubyType::toVariant( rb_ary_entry(value,1) ) ); } }; #endif /// \internal template<> struct RubyType { inline static VALUE toVALUE(const TQPoint& s) { VALUE l = rb_ary_new(); rb_ary_push(l, RubyType::toVALUE(s.x())); rb_ary_push(l, RubyType::toVALUE(s.y())); return l; } inline static TQPoint toVariant(VALUE value) { #ifdef HAVE_RUBY_1_9 if( TYPE(value) != T_ARRAY || RARRAY_LEN(value) != 2 ) { #else if( TYPE(value) != T_ARRAY || RARRAY(value)->len != 2 ) { #endif rb_raise(rb_eTypeError, "TQPoint must be an array with 2 elements"); return TQPoint(); } return TQPoint( RubyType::toVariant( rb_ary_entry(value,0) ), RubyType::toVariant( rb_ary_entry(value,1) ) ); } }; #if 0 /// \internal template<> struct RubyType { inline static VALUE toVALUE(const TQPointF& s) { VALUE l = rb_ary_new(); rb_ary_push(l, RubyType::toVALUE(s.x())); rb_ary_push(l, RubyType::toVALUE(s.y())); return l; } inline static TQPointF toVariant(VALUE value) { #ifdef HAVE_RUBY_1_9 if( TYPE(value) != T_ARRAY || RARRAY_LEN(value) != 2 ) { #else if( TYPE(value) != T_ARRAY || RARRAY(value)->len != 2 ) { #endif rb_raise(rb_eTypeError, "TQPointF must be an array with 2 elements"); return TQPointF(); } return TQPointF( RubyType::toVariant( rb_ary_entry(value,0) ), RubyType::toVariant( rb_ary_entry(value,1) ) ); } }; #endif /// \internal template<> struct RubyType { inline static VALUE toVALUE(const TQRect& s) { VALUE l = rb_ary_new(); rb_ary_push(l, RubyType::toVALUE(s.x())); rb_ary_push(l, RubyType::toVALUE(s.y())); rb_ary_push(l, RubyType::toVALUE(s.width())); rb_ary_push(l, RubyType::toVALUE(s.height())); return l; } inline static TQRect toVariant(VALUE value) { #ifdef HAVE_RUBY_1_9 if( TYPE(value) != T_ARRAY || RARRAY_LEN(value) != 4 ) { #else if( TYPE(value) != T_ARRAY || RARRAY(value)->len != 4 ) { #endif rb_raise(rb_eTypeError, "TQRect must be an array with 4 elements"); return TQRect(); } return TQRect( RubyType::toVariant( rb_ary_entry(value,0) ), RubyType::toVariant( rb_ary_entry(value,1) ), RubyType::toVariant( rb_ary_entry(value,2) ), RubyType::toVariant( rb_ary_entry(value,3) ) ); } }; #if 0 /// \internal template<> struct RubyType { inline static VALUE toVALUE(const TQRectF& s) { VALUE l = rb_ary_new(); rb_ary_push(l, RubyType::toVALUE(s.x())); rb_ary_push(l, RubyType::toVALUE(s.y())); rb_ary_push(l, RubyType::toVALUE(s.width())); rb_ary_push(l, RubyType::toVALUE(s.height())); return l; } inline static TQRectF toVariant(VALUE value) { #ifdef HAVE_RUBY_1_9 if( TYPE(value) != T_ARRAY || RARRAY_LEN(value) != 4 ) { #else if( TYPE(value) != T_ARRAY || RARRAY(value)->len != 4 ) { #endif rb_raise(rb_eTypeError, "TQRectF must be an array with 4 elements"); return TQRectF(); } return TQRectF( RubyType::toVariant( rb_ary_entry(value,0) ), RubyType::toVariant( rb_ary_entry(value,1) ), RubyType::toVariant( rb_ary_entry(value,2) ), RubyType::toVariant( rb_ary_entry(value,3) ) ); } }; #endif /// \internal template<> struct RubyType { inline static VALUE toVALUE(const TQUrl& url) { return RubyType::toVALUE( url.toString() ); } inline static TQUrl toVariant(VALUE value) { return TQUrl( RubyType::toVariant(value) ); } }; /// \internal template<> struct RubyType { inline static VALUE toVALUE(const TQStringList& list) { VALUE l = rb_ary_new(); for (TQStringList::const_iterator it = list.begin(); it != list.end(); ++it) { rb_ary_push(l, RubyType::toVALUE(*it)); } return l; } inline static TQStringList toVariant(VALUE value) { if( TYPE(value) != T_ARRAY ) { rb_raise(rb_eTypeError, "TQStringList must be an array"); return TQStringList(); } TQStringList l; #ifdef HAVE_RUBY_1_9 for(int i = 0; i < RARRAY_LEN(value); i++) #else for(int i = 0; i < RARRAY(value)->len; i++) #endif l.append( RubyType::toVariant( rb_ary_entry(value, i) ) ); return l; } }; #if 0 /// \internal template<> struct RubyType { inline static VALUE toVALUE(const TQVariantList& list) { VALUE l = rb_ary_new(); foreach(TQVariant v, list) rb_ary_push(l, RubyType::toVALUE(v)); return l; } inline static TQVariantList toVariant(VALUE value) { if( TYPE(value) != T_ARRAY ) { rb_raise(rb_eTypeError, "TQVariantList must be an array"); return TQVariantList(); } TQVariantList l; #ifdef HAVE_RUBY_1_9 for(int i = 0; i < RARRAY_LEN(value); i++) #else for(int i = 0; i < RARRAY(value)->len; i++) #endif l.append( RubyType::toVariant( rb_ary_entry(value, i) ) ); return l; } }; #endif #if 0 /// \internal template<> struct RubyType { inline static VALUE toVALUE(const TQVariantMap& map) { VALUE h = rb_hash_new(); TQMap::ConstIterator it(map.constBegin()), end(map.end()); for(; it != end; ++it) rb_hash_aset(h, RubyType::toVALUE(it.key()), RubyType::toVALUE(it.value()) ); return h; } inline static int convertHash(VALUE key, VALUE value, VALUE vmap) { TQVariantMap* map; Data_Get_Struct(vmap, TQVariantMap, map); if (key != TQundef) map->insert(STR2CSTR(key), RubyType::toVariant(value)); return ST_CONTINUE; } inline static TQVariantMap toVariant(VALUE value) { if( TYPE(value) != T_HASH ) { rb_raise(rb_eTypeError, "TQVariantMap must be a hash"); return TQVariantMap(); } TQVariantMap map; VALUE vmap = Data_Wrap_Struct(rb_cObject, 0,0, &map); rb_hash_foreach(value, (int (*)(...))convertHash, vmap); return map; } }; #endif #if 0 /** * The RubyMetaTypeFactory helper class us used as factory within * \a RubyExtension to translate an argument into a \a MetaType * needed for TQGenericArgument's data pointer. */ class RubyMetaTypeFactory { public: static MetaType* create(int typeId, int metaTypeId, VALUE valueect = TQnil); }; /// \internal template class RubyMetaTypeVariant : public MetaTypeVariant { public: RubyMetaTypeVariant(VALUE value) : MetaTypeVariant( (TYPE(value) == T_NIL) ? TQVariant().value() : RubyType::toVariant(value) ) {} virtual ~RubyMetaTypeVariant() {} }; #endif } #endif