diff options
-rw-r--r-- | lib/kross/ruby/rubyvariant.h | 559 |
1 files changed, 559 insertions, 0 deletions
diff --git a/lib/kross/ruby/rubyvariant.h b/lib/kross/ruby/rubyvariant.h new file mode 100644 index 00000000..d0d25759 --- /dev/null +++ b/lib/kross/ruby/rubyvariant.h @@ -0,0 +1,559 @@ +/*************************************************************************** + * rubyvariant.h + * This file is part of the KDE project + * copyright (C)2005 by Cyrille Berger ([email protected]) + * copyright (C)2006 by Sebastian Sauer ([email protected]) + * + * 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 <ruby.h> + +#ifndef HAVE_RUBY_1_9 +#include <st.h> +#else // HAVE_RUBY_1_9 +#include <ruby/st.h> +#endif // HAVE_RUBY_1_9 +//#include <typeinfo> + +#include "rubyconfig.h" + +#include <tqstring.h> +#include <tqstringlist.h> +#include <tqvariant.h> +#include <tqsize.h> +#include <tqpoint.h> +#include <tqrect.h> +#include <tqurl.h> +#include <tqdatetime.h> + +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<typename VARIANTTYPE, typename RBTYPE = VALUE> + 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<TQVariant> + { + static VALUE toVALUE(const TQVariant& v); + static TQVariant toVariant(VALUE value); + }; + + /// \internal + template<> + struct RubyType<int> + { + 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<uint> + { + 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<double> + { + inline static VALUE toVALUE(double d) { + return rb_float_new(d); + } + inline static double toVariant(VALUE value) { + return NUM2DBL(value); + } + }; + + /// \internal + template<> + struct RubyType<bool> + { + 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<TQ_LLONG> + { + 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<TQ_ULLONG> + { + 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<TQByteArray> + { + 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<TQString> + { + 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<TQSize> + { + inline static VALUE toVALUE(const TQSize& s) { + VALUE l = rb_ary_new(); + rb_ary_push(l, RubyType<int>::toVALUE(s.width())); + rb_ary_push(l, RubyType<int>::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<int>::toVariant( rb_ary_entry(value,0) ), RubyType<int>::toVariant( rb_ary_entry(value,1) ) ); + } + }; + +#if 0 + /// \internal + template<> + struct RubyType<TQSizeF> + { + inline static VALUE toVALUE(const TQSizeF& s) { + VALUE l = rb_ary_new(); + rb_ary_push(l, RubyType<double>::toVALUE(s.width())); + rb_ary_push(l, RubyType<double>::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<double>::toVariant( rb_ary_entry(value,0) ), RubyType<double>::toVariant( rb_ary_entry(value,1) ) ); + + } + }; +#endif + + /// \internal + template<> + struct RubyType<TQPoint> + { + inline static VALUE toVALUE(const TQPoint& s) { + VALUE l = rb_ary_new(); + rb_ary_push(l, RubyType<int>::toVALUE(s.x())); + rb_ary_push(l, RubyType<int>::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<int>::toVariant( rb_ary_entry(value,0) ), RubyType<int>::toVariant( rb_ary_entry(value,1) ) ); + } + }; + +#if 0 + /// \internal + template<> + struct RubyType<TQPointF> + { + inline static VALUE toVALUE(const TQPointF& s) { + VALUE l = rb_ary_new(); + rb_ary_push(l, RubyType<double>::toVALUE(s.x())); + rb_ary_push(l, RubyType<double>::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<double>::toVariant( rb_ary_entry(value,0) ), RubyType<double>::toVariant( rb_ary_entry(value,1) ) ); + } + }; +#endif + + /// \internal + template<> + struct RubyType<TQRect> + { + inline static VALUE toVALUE(const TQRect& s) { + VALUE l = rb_ary_new(); + rb_ary_push(l, RubyType<int>::toVALUE(s.x())); + rb_ary_push(l, RubyType<int>::toVALUE(s.y())); + rb_ary_push(l, RubyType<int>::toVALUE(s.width())); + rb_ary_push(l, RubyType<int>::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<int>::toVariant( rb_ary_entry(value,0) ), RubyType<int>::toVariant( rb_ary_entry(value,1) ), + RubyType<int>::toVariant( rb_ary_entry(value,2) ), RubyType<int>::toVariant( rb_ary_entry(value,3) ) ); + } + }; + +#if 0 + /// \internal + template<> + struct RubyType<TQRectF> + { + inline static VALUE toVALUE(const TQRectF& s) { + VALUE l = rb_ary_new(); + rb_ary_push(l, RubyType<double>::toVALUE(s.x())); + rb_ary_push(l, RubyType<double>::toVALUE(s.y())); + rb_ary_push(l, RubyType<double>::toVALUE(s.width())); + rb_ary_push(l, RubyType<double>::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<double>::toVariant( rb_ary_entry(value,0) ), RubyType<double>::toVariant( rb_ary_entry(value,1) ), + RubyType<double>::toVariant( rb_ary_entry(value,2) ), RubyType<double>::toVariant( rb_ary_entry(value,3) ) ); + } + }; +#endif + + /// \internal + template<> + struct RubyType<TQUrl> + { + inline static VALUE toVALUE(const TQUrl& url) { + return RubyType<TQString>::toVALUE( url.toString() ); + } + inline static TQUrl toVariant(VALUE value) { + return TQUrl( RubyType<TQString>::toVariant(value) ); + } + }; + + /// \internal + template<> + struct RubyType<TQStringList> + { + 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<TQString>::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<TQString>::toVariant( rb_ary_entry(value, i) ) ); + return l; + } + }; + +#if 0 + /// \internal + template<> + struct RubyType<TQVariantList> + { + inline static VALUE toVALUE(const TQVariantList& list) { + VALUE l = rb_ary_new(); + foreach(TQVariant v, list) + rb_ary_push(l, RubyType<TQVariant>::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<TQVariant>::toVariant( rb_ary_entry(value, i) ) ); + return l; + } + }; +#endif + +#if 0 + /// \internal + template<> + struct RubyType<TQVariantMap> + { + inline static VALUE toVALUE(const TQVariantMap& map) { + VALUE h = rb_hash_new(); + TQMap<TQString, TQVariant>::ConstIterator it(map.constBegin()), end(map.end()); + for(; it != end; ++it) + rb_hash_aset(h, RubyType<TQString>::toVALUE(it.key()), RubyType<TQVariant>::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<TQVariant>::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<typename VARIANTTYPE> + class RubyMetaTypeVariant : public MetaTypeVariant<VARIANTTYPE> + { + public: + RubyMetaTypeVariant(VALUE value) + : MetaTypeVariant<VARIANTTYPE>( + (TYPE(value) == T_NIL) + ? TQVariant().value<VARIANTTYPE>() + : RubyType<VARIANTTYPE>::toVariant(value) + ) {} + + virtual ~RubyMetaTypeVariant() {} + }; + +#endif + +} + +#endif + |