diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 90825e2392b2d70e43c7a25b8a3752299a933894 (patch) | |
tree | e33aa27f02b74604afbfd0ea4f1cfca8833d882a /qtruby/rubylib/qtruby/smokeruby.h | |
download | tdebindings-90825e2392b2d70e43c7a25b8a3752299a933894.tar.gz tdebindings-90825e2392b2d70e43c7a25b8a3752299a933894.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebindings@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'qtruby/rubylib/qtruby/smokeruby.h')
-rw-r--r-- | qtruby/rubylib/qtruby/smokeruby.h | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/qtruby/rubylib/qtruby/smokeruby.h b/qtruby/rubylib/qtruby/smokeruby.h new file mode 100644 index 00000000..8f152c10 --- /dev/null +++ b/qtruby/rubylib/qtruby/smokeruby.h @@ -0,0 +1,321 @@ +#ifndef SMOKERUBY_H +#define SMOKERUBY_H + +#include "smoke.h" + +#undef DEBUG +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#ifndef __USE_POSIX +#define __USE_POSIX +#endif +#ifndef __USE_XOPEN +#define __USE_XOPEN +#endif +#include "ruby.h" + +#include <qcstring.h> + +#include "qtruby.h" +#include "marshall.h" + + +class SmokeRuby; + +class SmokeType { + Smoke::Type *_t; // derived from _smoke and _id, but cached + + Smoke *_smoke; + Smoke::Index _id; +public: + SmokeType() : _t(0), _smoke(0), _id(0) {} + SmokeType(Smoke *s, Smoke::Index i) : _smoke(s), _id(i) { + if(_id < 0 || _id > _smoke->numTypes) _id = 0; + _t = _smoke->types + _id; + } + // default copy constructors are fine, this is a constant structure + + // mutators + void set(Smoke *s, Smoke::Index i) { + _smoke = s; + _id = i; + _t = _smoke->types + _id; + } + + // accessors + Smoke *smoke() const { return _smoke; } + Smoke::Index typeId() const { return _id; } + const Smoke::Type &type() const { return *_t; } + unsigned short flags() const { return _t->flags; } + unsigned short elem() const { return _t->flags & Smoke::tf_elem; } + const char *name() const { return _t->name; } + Smoke::Index classId() const { return _t->classId; } + + // tests + bool isStack() const { return ((flags() & Smoke::tf_ref) == Smoke::tf_stack); } + bool isPtr() const { return ((flags() & Smoke::tf_ref) == Smoke::tf_ptr); } + bool isRef() const { return ((flags() & Smoke::tf_ref) == Smoke::tf_ref); } + bool isConst() const { return (flags() & Smoke::tf_const); } + bool isClass() const { + if(elem() == Smoke::t_class) + return classId() ? true : false; + return false; + } + + bool operator ==(const SmokeType &b) const { + const SmokeType &a = *this; + if(a.name() == b.name()) return true; + if(a.name() && b.name() && qstrcmp(a.name(), b.name()) == 0) + return true; + return false; + } + bool operator !=(const SmokeType &b) const { + const SmokeType &a = *this; + return !(a == b); + } + +}; + +class SmokeClass { + Smoke::Class *_c; + Smoke *_smoke; + Smoke::Index _id; +public: + SmokeClass(const SmokeType &t) { + _smoke = t.smoke(); + _id = t.classId(); + _c = _smoke->classes + _id; + } + SmokeClass(Smoke *smoke, Smoke::Index id) : _smoke(smoke), _id(id) { + _c = _smoke->classes + _id; + } + + Smoke *smoke() const { return _smoke; } + const Smoke::Class &c() const { return *_c; } + Smoke::Index classId() const { return _id; } + const char *className() const { return _c->className; } + Smoke::ClassFn classFn() const { return _c->classFn; } + Smoke::EnumFn enumFn() const { return _c->enumFn; } + bool operator ==(const SmokeClass &b) const { + const SmokeClass &a = *this; + if(a.className() == b.className()) return true; + if(a.className() && b.className() && qstrcmp(a.className(), b.className()) == 0) + return true; + return false; + } + bool operator !=(const SmokeClass &b) const { + const SmokeClass &a = *this; + return !(a == b); + } + bool isa(const SmokeClass &sc) const { + // This is a sick function, if I do say so myself + if(*this == sc) return true; + Smoke::Index *parents = _smoke->inheritanceList + _c->parents; + for(int i = 0; parents[i]; i++) { + if(SmokeClass(_smoke, parents[i]).isa(sc)) return true; + } + return false; + } + + unsigned short flags() const { return _c->flags; } + bool hasConstructor() const { return flags() & Smoke::cf_constructor; } + bool hasCopy() const { return flags() & Smoke::cf_deepcopy; } + bool hasVirtual() const { return flags() & Smoke::cf_virtual; } + bool hasFire() const { return !(flags() & Smoke::cf_undefined); } +}; + +class SmokeMethod { + Smoke::Method *_m; + Smoke *_smoke; + Smoke::Index _id; +public: + SmokeMethod(Smoke *smoke, Smoke::Index id) : _smoke(smoke), _id(id) { + _m = _smoke->methods + _id; + } + + Smoke *smoke() const { return _smoke; } + const Smoke::Method &m() const { return *_m; } + SmokeClass c() const { return SmokeClass(_smoke, _m->classId); } + const char *name() const { return _smoke->methodNames[_m->name]; } + int numArgs() const { return _m->numArgs; } + unsigned short flags() const { return _m->flags; } + SmokeType arg(int i) const { + if(i >= numArgs()) return SmokeType(); + return SmokeType(_smoke, _smoke->argumentList[_m->args + i]); + } + SmokeType ret() const { return SmokeType(_smoke, _m->ret); } + Smoke::Index methodId() const { return _id; } + Smoke::Index method() const { return _m->method; } + + bool isStatic() const { return flags() & Smoke::mf_static; } + bool isConst() const { return flags() & Smoke::mf_const; } + + void call(Smoke::Stack args, void *ptr = 0) const { + Smoke::ClassFn fn = c().classFn(); + (*fn)(method(), ptr, args); + } +}; + +class Smoke_MAGIC { // to be rewritten + SmokeClass _c; + void *_ptr; + bool _isAllocated; +public: + Smoke_MAGIC(void *p, const SmokeClass &c) : + _c(c), _ptr(p), _isAllocated(false) {} + const SmokeClass &c() const { return _c; } + void *ptr() const { return _ptr; } + bool isAllocated() const { return _isAllocated; } + void setAllocated(bool isAllocated) { _isAllocated = isAllocated; } +}; + + +/** + * SmokeObject is a thin wrapper around VALUE objects. Each SmokeObject instance + * increments the refcount of its VALUE for the duration of its existance. + * + * SmokeObject instances are only returned from SmokeRuby, since the method + * of binding data to the scalar must be consistent across all modules. + */ +class SmokeObject { + VALUE rv; + Smoke_MAGIC *m; + +public: + SmokeObject(VALUE obj, Smoke_MAGIC *mag) : rv(obj), m(mag) { + rb_gc_register_address(&rv); + } + + ~SmokeObject() { + rb_gc_unregister_address(&rv); + } + + SmokeObject(const SmokeObject &other) { + rv = other.rv; + m = other.m; + rb_gc_register_address(&rv); + } + + SmokeObject &operator =(const SmokeObject &other) { + rv = other.rv; + m = other.m; + rb_gc_register_address(&rv); + return *this; + } + + const SmokeClass &c() { return m->c(); } + Smoke *smoke() { return c().smoke(); } + VALUE * var() { return &rv; } + void *ptr() { return m->ptr(); } + Smoke::Index classId() { return c().classId(); } + void *cast(const SmokeClass &toc) { + return smoke()->cast( + ptr(), + classId(), + smoke()->idClass(toc.className()) + ); + } + const char *className() { return c().className(); } + + bool isValid() const { return !NIL_P(rv); } + bool isAllocated() const { return m->isAllocated(); } + void setAllocated(bool i) { m->setAllocated(i); } +}; + + +/** + * Since it's not easy to share functions between Ruby modules, the common + * interface between all Smoked libraries and Ruby will be defined in this + * class. There will be only one SmokeRuby instance loaded for an entire Ruby + * process. It has no data members here -- this is only an abstract interface. + */ + +class SmokeRuby { + void *future_extension; +public: + SmokeRuby() : future_extension(0) {} + + // don't need this, we're only defining an interface + virtual ~SmokeRuby() = 0; + + /** + * Registers a Smoke object + */ + virtual void registerSmoke(const char *name, Smoke *smoke) = 0; + + /** + * Gets a smoke object from its name + */ + virtual Smoke *getSmoke(const char *name) = 0; + + /** + * Determines if the named smoke is registered. + */ + bool isSmokeRegistered(const char *name) { return getSmoke(name) ? true : false; } + + virtual void registerHandlers(TypeHandler *handlers) = 0; + + /** + * Returns a new blessed SV referring to the pointer passed. + * Use sv_2mortal() before passing it around. + * + * @param p pointer to the C++ object. The pointer isn't automatically deleted by SmokePerl. + * @param c class of the pointer + * @see #getObject + * @see #deleteObject + */ + virtual SmokeObject newObject(void *p, const SmokeClass &c) = 0; + + /** + * Same as newObject(), except it doesn't treat p as owned by Perl + */ + virtual SmokeObject wrapObject(void *p, const SmokeClass &c) = 0; + + /** + * Any SV* created with newObject() on a class with virtual methods can be + * retrieved again. + */ + virtual SmokeObject getObject(void *p) = 0; + + /** + * Create a SmokeObject from the given VALUE + */ + virtual SmokeObject getObject(VALUE value) = 0; +}; + +/* + * Type handling by moc is simple. + * + * If the type name matches /^(?:const\s+)?\Q$types\E&?$/, use the + * static_QUType, where $types is join('|', qw(bool int double char* QString); + * + * Everything else is passed as a pointer! There are types which aren't + * Smoke::tf_ptr but will have to be passed as a pointer. Make sure to keep + * track of what's what. + */ + +/* + * Simply using typeids isn't enough for signals/slots. It will be possible + * to declare signals and slots which use arguments which can't all be + * found in a single smoke object. Instead, we need to store smoke => typeid + * pairs. We also need additional informatation, such as whether we're passing + * a pointer to the union element. + */ + +enum MocArgumentType { + xmoc_ptr, + xmoc_bool, + xmoc_int, + xmoc_double, + xmoc_charstar, + xmoc_QString +}; + +struct MocArgument { + // smoke object and associated typeid + SmokeType st; + MocArgumentType argType; +}; + +#endif // SMOKERUBY_H |