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.
koffice/lib/kross/ruby/rubyvariant.h

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<TQStringVariantMap>
{
inline static VALUE toVALUE(const TQStringVariantMap& map) {
VALUE h = rb_hash_new();
TQStringVariantMap::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) {
TQStringVariantMap* map;
Data_Get_Struct(vmap, TQStringVariantMap, map);
if (key != TQundef)
map->insert(STR2CSTR(key), RubyType<TQVariant>::toVariant(value));
return ST_CONTINUE;
}
inline static TQStringVariantMap toVariant(VALUE value) {
if( TYPE(value) != T_HASH ) {
rb_raise(rb_eTypeError, "TQStringVariantMap must be a hash");
return TQStringVariantMap();
}
TQStringVariantMap 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