You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
561 lines
18 KiB
561 lines
18 KiB
/***************************************************************************
|
|
* 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 <ruby.h>
|
|
|
|
#ifndef HAVE_RUBY_1_9
|
|
#include <st.h>
|
|
#else // HAVE_RUBY_1_9
|
|
#include <ruby/st.h>
|
|
#define STR2CSTR(x) StringValuePtr(x)
|
|
#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
|
|
|