Added GPLv3 headers all over the place.
[fail.git] / src / services / python / class.h
bloba19afcfbc7e4da5a5d57423212295e41a850d98d
1 /*
2 Fail game engine
3 Copyright 2007 Antoine Chavasse <a.chavasse@gmail.com>
5 This file is part of Fail.
7 Fail is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 3
9 as published by the Free Software Foundation.
11 Fail is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #ifndef FAIL_PYTHON_CLASS_H
20 #define FAIL_PYTHON_CLASS_H
22 #include "core/core.h"
23 #include <string>
24 #include <vector>
25 #include <type_traits>
27 namespace fail { namespace PythonImpl
29 template< bool DoWant, class C > struct RegisterIf
31 static void RegisterPointerConversion()
33 TypeConverter< NormalType, Pointer< C > >::RegisterPointerConversion();
37 template< class C > struct RegisterIf< false, C >
39 static void RegisterPointerConversion()
44 template< class C, typename AttrTag, typename Category = typename attribute_traits< C, AttrTag >::category,
45 bool bReadOnly = flags::ReadOnly< AttrTag >::value,
46 bool bUnMutable = flags::Mutable< AttrTag >::value >
47 struct ClassAttrGetter
49 static PyObject* GetAttr( PyObject* pPyObj, void* )
51 typedef TypeConverter< NormalType, Pointer< C > > obj_tc;
52 Pointer< C > pObj;
53 obj_tc::ConvertFromPython_nocheck( pPyObj, pObj );
55 typedef attribute_traits< C, AttrTag > traits;
56 typedef TypeConverter< typename traits::category, typename traits::type > tc;
58 return tc::ConvertToPython( ( pObj->*traits::Getter() )() );
62 template< class C, typename AttrTag >
63 struct ClassAttrGetter< C, AttrTag, StructType, false, true >
65 static PyObject* GetAttr( PyObject* pPyObj, void* )
67 typedef TypeConverter< NormalType, Pointer< C > > obj_tc;
68 Pointer< C > pObj;
69 obj_tc::ConvertFromPython_nocheck( pPyObj, pObj );
71 typedef attribute_traits< C, AttrTag > traits;
72 typedef TypeConverter< typename traits::category, typename traits::type > tc;
74 return tc::ConvertToPythonByRef( pObj, ( pObj->*traits::GetterMutable() )() );
78 // Holds all necessary static data and utility sub classes related to a class
79 template< class C > struct ClassStuff
81 static PyTypeObject TypeObject;
82 static std::vector< PyMethodDef > Methods;
83 static std::vector< PyGetSetDef > Attributes;
84 static std::map< std::string, int32_t > Constants;
86 // This is the python representation of instances of the structure at hand. Just the
87 // structure wrapped into a PyObject.
88 struct Wrapper : public PyObject // I don't have to use their shitty little macro
89 // that fakes inheritance in C.
91 Wrapper() :
92 pTypeCastMap( &TypeCasts< C >::Map )
96 Wrapper( const Pointer< C >& pObj_ ) :
97 pObj( pObj_ ),
98 pTypeCastMap( &TypeCasts< C >::Map )
102 Pointer< C > pObj;
103 TypeCastMap* pTypeCastMap;
106 // The callcontext to be used by all struct method wrappers. The wrappers themselves
107 // are actually mostly the same for structs and classes, only bits of the callcontext
108 // need to be tweaked for either case.
109 struct Class_CallContext : public CallContext< C, NormalType, Pointer< C > >
111 Class_CallContext( PyObject* pPyObj_, PyObject* pArgs_ ) :
112 CallContext< C, NormalType, Pointer< C > >( pPyObj_, pArgs_ )
116 template< typename... Args > void constructObject( Args&&... args_ )
118 Wrapper* pWrapper = static_cast< Wrapper* >( CallContext< C, NormalType, Pointer< C > >::m_pPyObj );
119 new( pWrapper ) Wrapper;
120 pWrapper->pObj = new C( args_... );
124 // The python finalizer for that type. Calls the destructor of the wrapped struct.
125 static void DeleteFunc( PyObject* pPyObj )
127 Wrapper* pWrapper = static_cast< Wrapper* >( pPyObj );
129 // Call the Pointer's destructor.
130 pWrapper->pObj.~Pointer< C >();
132 pPyObj->ob_type->tp_free( pPyObj );
135 static PyObject* GlobalGetAttr( PyObject* pPyObj, PyObject* pName )
137 const char* pAttrName = PyString_AS_STRING( pName );
139 std::map< std::string, int32_t >::const_iterator it = Constants.find( pAttrName );
140 if( it != Constants.end() )
141 return PyInt_FromLong( it->second );
143 return PyObject_GenericGetAttr( pPyObj, pName );
146 template< typename AttrTag > static PyObject* GetAttr( PyObject* pPyObj, void* )
148 typedef attribute_traits< C, AttrTag > traits;
149 typedef TypeConverter< typename traits::category, typename traits::type > tc;
151 Wrapper* pWrapper = static_cast< Wrapper* >( pPyObj );
152 return tc::ConvertToPython( ( pWrapper->pObj->*traits::Getter() )() );
155 template< typename AttrTag > static int SetAttr( PyObject* pPyObj, PyObject *pValue, void* )
159 typedef attribute_traits< C, AttrTag > traits;
160 typedef TypeConverter< typename traits::category, typename traits::type > tc;
162 Wrapper* pWrapper = static_cast< Wrapper* >( pPyObj );
164 typename traits::type Value;
165 tc::ConvertFromPython( pValue, Value );
167 ( pWrapper->pObj->*traits::Setter() )( Value );
169 return 0;
171 catch( const Error::Base& error )
173 error.ConvertToPython();
174 return -1;
178 // Visitor callback used to count things to reserve buffers.
179 struct CountVisitor
181 CountVisitor() : MethodCount( 0 ), AttributeCount( 0 ) {}
183 void declConstructor()
187 template< typename MtdTag > void declMethod()
189 if( flags::Scriptable< MtdTag >::value )
190 ++MethodCount;
193 template< typename MtdTag > void declStaticMethod()
195 if( flags::Scriptable< MtdTag >::value )
196 ++MethodCount;
199 template< typename AttrTag > void declAttribute()
201 if( flags::Scriptable< AttrTag >::value )
202 ++AttributeCount;
205 template< class SC > void declSuperClass()
207 if( flags::Scriptable< SC >::value )
209 class_traits< SC >::VisitMethods( *this );
210 class_traits< SC >::VisitAttributes( *this );
214 int MethodCount;
215 int AttributeCount;
218 // Visitor callback used to walk through all the stuff the class has to offer, and setup the
219 // necessary wrappers.
220 struct SetupVisitor
222 void declConstructor()
224 if( flags::Scriptable< typename class_traits< C >::ctor_tag >::value )
225 TypeObject.tp_new = &CtorWrapper< C, Class_CallContext >::PyFunc;
228 template< typename MtdTag > void declMethod()
230 if( !flags::Scriptable< MtdTag >::value )
231 return;
233 PyMethodDef def;
234 def.ml_name = method_traits< C, MtdTag >::Name();
235 def.ml_meth = &MethodWrapper< C, MtdTag, Class_CallContext >::PyFunc;
236 def.ml_flags = METH_VARARGS;
237 def.ml_doc = NULL;
238 Methods.push_back( def );
241 template< typename MtdTag > void declStaticMethod()
243 if( !flags::Scriptable< MtdTag >::value )
244 return;
246 PyMethodDef def;
247 def.ml_name = method_traits< C, MtdTag >::Name();
248 def.ml_meth = &MethodWrapper< C, MtdTag, Class_CallContext >::PyFunc;
249 def.ml_flags = METH_VARARGS | METH_STATIC;
250 def.ml_doc = NULL;
251 Methods.push_back( def );
254 // This stuff is there to conditionally instantiate the attribute wrapping
255 // code.
257 // Just a plain if doesn't work because the attribute wrapping code
258 // is instantiated before getting discarded by the optimizer, and we don't
259 // want this code to be instantiated at all so we're not forced to
260 // define accessors for non-scriptable attributes.
261 template< typename AttrTag > struct DoNotWantAttribute
263 static void setup( SetupVisitor& sv ) {}
266 template< typename AttrTag > struct DoWantAttribute
268 static void setup( SetupVisitor& sv )
270 sv.setupAttribute< AttrTag >();
274 template< typename AttrTag > void declAttribute()
276 //call_member_if< flags::scriptable< AttrTag >::value >
277 typedef std::conditional<
278 flags::Scriptable< AttrTag >::value,
279 DoWantAttribute< AttrTag >,
280 DoNotWantAttribute< AttrTag > > AttrSetupProxy;
281 AttrSetupProxy::type::setup( *this );
284 template< typename AttrTag > void setupAttribute()
286 PyGetSetDef def;
288 // "How do I used const" -- probably said at one point or another by some drooling python developer
289 def.name = const_cast< char* >( attribute_traits< C, AttrTag >::Name() );
290 def.get = ClassAttrGetter< C, AttrTag >::GetAttr;
291 def.set = SetAttr< AttrTag >;
292 def.doc = NULL;
293 def.closure = NULL;
294 Attributes.push_back( def );
297 // Simplistic enum implementation: enum values are converted to/from integers,
298 // and are defined as read only integer attributes of the object.
299 // So there's no type enforcement like in the lua bindings.
300 template< typename EnumTag > void declEnum()
302 if( !flags::Scriptable< EnumTag >::value )
303 return;
305 enum_traits< C, EnumTag >::VisitValues( *this );
308 template< typename enum_type > void declEnumValue( const char* pName_, enum_type Value_ )
310 Constants[pName_] = Value_;
313 template< class SC > void declSuperClass()
315 if( !flags::Scriptable< SC >::value )
316 return;
318 class_traits< SC >::VisitSuperClasses( *this );
320 TypeCasts< C >::Map.insert( std::make_pair(
321 &ClassStuff< SC >::TypeObject,
322 &TypeCasts< C >::template PointerCastFunc< SC > ) );
324 class_traits< SC >::VisitMethods( *this );
325 class_traits< SC >::VisitAttributes( *this );
326 class_traits< SC >::VisitEnums( *this );
330 static void Setup( PyObject* pModule_ )
332 // It's really appalling to have to initialize this fucking structure manually like that.
333 // Did they ever hear of opaqueness? Who let those guys design their own programming language?
334 TypeObject.ob_type = &PyType_Type;
335 TypeObject.tp_basicsize = sizeof( Wrapper );
337 // The name's supposed to use dots as separators but I'm lazy
338 // and if Python didn't suck that much it would prepend the
339 // module name automatically as needed.
340 TypeObject.tp_name = class_traits< C >::FullName();
341 TypeObject.tp_flags = Py_TPFLAGS_DEFAULT;
343 TypeObject.tp_alloc = PyType_GenericAlloc;
345 // The C standard state that all identifiers beginning with an underscore are reserved for internal
346 // use by the compiler and the standard libraries. But the Python devs are so awesome that
347 // they are above rules and clean coding practices.
348 TypeObject.tp_free = _PyObject_Del;
350 // So, dealloc is not the opposite of alloc as one might believe at first glance. It's the opposite of new.
351 // Programming languages designed by people with a poor grasp of vocabulary are always the best ones.
352 TypeObject.tp_dealloc = DeleteFunc;
354 TypeObject.tp_getattro = GlobalGetAttr;
356 Py_INCREF( &TypeObject );
358 RegisterIf< flags::GenericPtr< C >::value, C >::RegisterPointerConversion();
360 // Count the methods and attributes, then reserve the required amount of entries in the respective vectors.
361 CountVisitor cv;
362 class_traits< C >::VisitSuperClasses( cv );
363 class_traits< C >::VisitMethods( cv );
364 class_traits< C >::VisitStaticMethods( cv );
365 class_traits< C >::VisitAttributes( cv );
367 Methods.reserve( cv.MethodCount + 1 );
368 Attributes.reserve( cv.AttributeCount + 1 );
370 SetupVisitor sv;
372 // Setup the methods and attributes from the superclasses.
373 class_traits< C >::VisitSuperClasses( sv );
375 // Setup the constructor and static methods.
376 class_traits< C >::VisitStaticMethods( sv );
378 // Setup the non-static methods.
379 class_traits< C >::VisitMethods( sv );
381 PyMethodDef terminator = { 0, 0, 0, 0 };
382 Methods.push_back( terminator );
383 TypeObject.tp_methods = &Methods[0];
385 // Setup attributes.
386 class_traits< C >::VisitAttributes( sv );
387 PyGetSetDef attr_terminator = { 0, 0, 0, 0, 0 };
388 Attributes.push_back( attr_terminator );
389 TypeObject.tp_getset = &Attributes[0];
391 // Setup enums.
392 class_traits< C >::VisitEnums( sv );
394 PyType_Ready( &TypeObject );
396 // Ah, the joy of shitty C apis and their careless, braindead reliance on
397 // disgracious casts.
398 // I could have used a (very pretty) reinterpret_cast to directly cast
399 // the typeobject into a PyObject, except that it produces a warning about
400 // breaking strict aliasing rules.
401 // Since I don't want to disable that useful warning for the sake of python's
402 // stupidity, I found this ugly workaround.
403 // It was going to be ugly either way anyway because python's developers
404 // are tasteless morons.
405 PyModule_AddObject( pModule_, class_traits< C >::Name(), static_cast< PyObject* >( static_cast< void* >( &TypeObject ) ) );
409 // Because of their very convenient PyObject_HEAD_INIT macro designed to be used
410 // as part of an initialisation list, I can't just clear the whole thing and get
411 // it initialized properly afterwards, forcing me to supply this ridiculous initializer
412 // list full of zeros.
413 template< class S > PyTypeObject ClassStuff< S >::TypeObject =
414 { PyObject_HEAD_INIT(NULL)
415 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
416 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
418 template< class C > std::vector< PyMethodDef > ClassStuff< C >::Methods( 0 );
419 template< class C > std::vector< PyGetSetDef > ClassStuff< C >::Attributes( 0 );
420 template< class C > std::map< std::string, int32_t > ClassStuff< C >::Constants;
423 #endif