* Added command line tool example similar to 'sopranocmd'
[kdebindings.git] / ruby / krossruby / rubycallcache.cpp
blob2c01aaf140393f39981e1675324d77a3a72c4002
1 /***************************************************************************
2 * rubycallcache.cpp
3 * This file is part of the KDE project
4 * copyright (C)2006 by Cyrille Berger (cberger@cberger.net)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public License
15 * along with this program; see the file COPYING. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 ***************************************************************************/
20 #include "rubycallcache.h"
21 #include "rubyvariant.h"
22 #include "rubyinterpreter.h"
24 #include <kross/core/manager.h>
25 #include <kross/core/metatype.h>
27 #include <QVariant>
28 #include <QMetaObject>
29 #include <QMetaMethod>
31 namespace Kross {
33 struct RubyCallCachePrivate
35 RubyCallCachePrivate(QObject* nobject, int nmethodindex, bool nhasreturnvalue, QVarLengthArray<int> ntypes, QVarLengthArray<int> nmetatypes)
36 : object(nobject), methodindex(nmethodindex), hasreturnvalue(nhasreturnvalue), types(ntypes), metatypes(nmetatypes)
39 QObject* object;
40 int methodindex;
41 QMetaMethod metamethod;
42 bool hasreturnvalue;
43 QVarLengthArray<int> types, metatypes;
44 static VALUE s_rccObject;
46 #ifdef KROSS_RUBY_CALLCACHE_CTORDTOR_DEBUG
47 /// \internal string for debugging.
48 QString debuginfo;
49 #endif
52 VALUE RubyCallCachePrivate::s_rccObject = 0;
54 RubyCallCache::RubyCallCache(QObject* object, int methodindex, bool hasreturnvalue, QVarLengthArray<int> ntypes, QVarLengthArray<int> nmetatypes)
55 : d(new RubyCallCachePrivate(object, methodindex, hasreturnvalue, ntypes, nmetatypes)), m_self(0)
57 Q_ASSERT(object);
58 d->metamethod = d->object->metaObject()->method(d->methodindex);
59 #ifdef KROSS_RUBY_CALLCACHE_CTORDTOR_DEBUG
60 d->debuginfo = QString("name=%1 class=%2 methodindex=%3 signature=%4").arg(object->objectName()).arg(object->metaObject()->className()).arg(d->methodindex).arg(d->metamethod.signature());
61 krossdebug( QString("RubyCallCache Ctor %1 ").arg(d->debuginfo) );
62 #endif
65 RubyCallCache::~RubyCallCache()
67 #ifdef KROSS_RUBY_CALLCACHE_CTORDTOR_DEBUG
68 krossdebug( QString("RubyCallCache Dtor %1 ").arg(d->debuginfo) );
69 #endif
70 delete d;
73 VALUE RubyCallCache::execfunction( int argc, VALUE *argv )
75 int typelistcount = d->types.count();
76 QVarLengthArray<MetaType*> variantargs( typelistcount );
77 QVarLengthArray<void*> voidstarargs( typelistcount );
79 #ifdef KROSS_RUBY_CALLCACHE_DEBUG
80 krossdebug( QString("RubyCallCache::execfunction signature=%1 typeName=%2 argc=%3 typelistcount=%4").arg(d->metamethod.signature()).arg(d->metamethod.typeName()).arg(argc).arg(typelistcount) );
81 for(int i = 0; i < d->types.count(); ++i)
82 krossdebug( QString(" argument index=%1 typeId=%2 typeName=%3 metaTypeId=%4").arg(i).arg(d->types[i]).arg(QVariant::typeToName( (QVariant::Type)d->types[i] )).arg(d->metatypes[i]) );
83 #endif
85 Q_ASSERT(argc >= typelistcount);
87 // set the return value
88 if(d->hasreturnvalue)
90 //krossdebug( QString("RubyCallCache::execfunction argv[1]=%1").arg(argc > 1 ? STR2CSTR(rb_inspect(argv[1])) : "") );
91 MetaType* returntype = RubyMetaTypeFactory::create( d->metamethod.typeName(), d->types[0], d->metatypes[0] );
92 //MetaType* returntype = RubyMetaTypeFactory::create( d->types[0], d->metatypes[0], argc > 1 ? argv[1] : Qnil );
93 variantargs[0] = returntype;
94 voidstarargs[0] = returntype->toVoidStar();
96 else
98 variantargs[0] = 0;
99 voidstarargs[0] = (void*)0;
102 // set the arguments values
103 QList<QByteArray> typelist = d->metamethod.parameterTypes();
104 for(int idx = 1; idx < typelistcount; ++idx)
106 #ifdef KROSS_RUBY_CALLCACHE_DEBUG
107 krossdebug( QString("RubyCallCache::execfunction param idx=%1 inspect=%2 QVariantType=%3 QMetaType=%4").arg(idx).arg(STR2CSTR(rb_inspect(argv[idx]))).arg(QVariant::typeToName((QVariant::Type)d->types[idx])).arg(QMetaType::typeName(d->metatypes[idx])) );
108 #endif
110 MetaType* metatype = RubyMetaTypeFactory::create( typelist[idx-1], d->types[idx], d->metatypes[idx], argv[idx] );
111 if(! metatype) { // Seems RubyMetaTypeFactory::create returned an invalid RubyType.
112 krosswarning( QString("RubyCallCache::execfunction Aborting cause RubyMetaTypeFactory::create returned NULL.") );
113 for(int i = 0; i < idx; ++i) // Clear already allocated instances.
114 delete variantargs[i];
115 return Qfalse; // abort execution.
117 variantargs[idx] = metatype;
118 voidstarargs[idx] = metatype->toVoidStar();
121 // call the method now
122 int r = d->object->qt_metacall(QMetaObject::InvokeMetaMethod, d->methodindex, &voidstarargs[0]);
123 #ifdef KROSS_RUBY_CALLCACHE_DEBUG
124 krossdebug( QString("RESULT nr=%1").arg(r) );
125 #else
126 Q_UNUSED(r);
127 #endif
129 // the return value
130 VALUE retvalue = 0;
132 // eval the return-value
133 if(d->hasreturnvalue)
135 QVariant result;
137 if( Kross::MetaTypeHandler* handler = Kross::Manager::self().metaTypeHandler(d->metamethod.typeName()) ) {
138 #ifdef KROSS_RUBY_CALLCACHE_DEBUG
139 krossdebug( QString("Returnvalue of type '%2' has a handler").arg(d->metamethod.typeName()) );
140 #endif
141 void *ptr = (*reinterpret_cast<void*(*)>( variantargs[0]->toVoidStar() ));
142 result = handler->callHandler(ptr);
144 else {
145 result = QVariant(variantargs[0]->typeId(), variantargs[0]->toVoidStar());
147 if( ! Kross::Manager::self().strictTypesEnabled() ) {
148 if( result.type() == QVariant::Invalid && QByteArray(d->metamethod.typeName()).endsWith("*") ) {
149 //#ifdef KROSS_RUBY_CALLCACHE_DEBUG
150 krossdebug( QString("Returnvalue of type '%2' will be reinterpret_cast<QObject*>").arg(d->metamethod.typeName()) );
151 //#endif
152 QObject* obj = (*reinterpret_cast<QObject*(*)>( variantargs[0]->toVoidStar() ));
153 result.setValue( (QObject*) obj );
158 #ifdef KROSS_RUBY_CALLCACHE_DEBUG
159 krossdebug( QString("RubyCallCache::execfunction Returnvalue typeId=%1 metamethod.typename=%2 variant.toString=%3 variant.typeName=%4").arg(variantargs[0]->typeId()).arg(d->metamethod.typeName()).arg(result.toString()).arg(result.typeName()) );
160 #endif
162 // set the return value
163 retvalue = RubyType<QVariant>::toVALUE(result);
166 // free the return-value and the arguments
167 for(int idx = 0; idx < typelistcount; ++idx)
169 delete variantargs[idx];
172 return retvalue;
175 void RubyCallCache::delete_object(void* object)
177 #ifdef KROSS_RUBY_CALLCACHE_CTORDTOR_DEBUG
178 krossdebug("RubyCallCache::delete_object");
179 #endif
180 RubyCallCache* callcache = static_cast< RubyCallCache* >(object);
181 delete callcache;
182 callcache = 0;
185 VALUE RubyCallCache::method_cacheexec(int argc, VALUE *argv, VALUE self)
187 #ifdef KROSS_RUBY_CALLCACHE_DEBUG
188 krossdebug("RubyCallCache::method_cacheexec");
189 #endif
190 RubyCallCache* callcache;
191 Data_Get_Struct(self, RubyCallCache, callcache);
192 return callcache->execfunction(argc, argv);
195 VALUE RubyCallCache::toValue()
197 if(m_self == 0)
199 if(RubyCallCachePrivate::s_rccObject == 0)
201 RubyCallCachePrivate::s_rccObject = rb_define_class_under(RubyInterpreter::krossModule(), "CallCache", rb_cObject);
202 rb_define_method(RubyCallCachePrivate::s_rccObject, "cacheexec", (VALUE (*)(...))RubyCallCache::method_cacheexec, -1);
204 m_self = Data_Wrap_Struct(RubyCallCachePrivate::s_rccObject, 0, RubyCallCache::delete_object, this);
206 return m_self;