All modules now compile again.
[fail.git] / src / blawful / pyawful / method.h
blob664696c7852632de2615584ea8c8a30e7cb41f78
1 #ifndef AWFUL_PYTHON_METHOD_H
2 #define AWFUL_PYTHON_METHOD_H
4 namespace awful { namespace PythonImpl
6 template< class C, typename obj_category, typename PointerT > struct CallContext
8 CallContext( PyObject* pPyObj_, PyObject* pArgs_ ) :
9 m_pPyObj( pPyObj_ ),
10 m_pArgs( pArgs_ ),
11 m_paramindex( 0 ),
12 m_pResult( 0 )
16 ~CallContext()
18 if( m_pResult )
20 // Fucking macros and their hidden synctactic nature. Is it a bunch of statements? A sub-scope?
21 // Some random fragment of code only valid in a very specific context? Apparently here it is just
22 // a naked group of statements so I need to add braces that serve no apparent purpose but
23 // do change the meaning of the code.
25 // If only the C standard provided a way to define functions that are expanded at their call site
26 // that could be used instead of those shitty macros...
27 // Wait, who am I kidding? Python's developers discovered "const" in 2007.
28 Py_DECREF( m_pResult );
32 int numParams() const
34 return PyTuple_GET_SIZE( m_pArgs );
37 void numExpectedParams( int Num_ ) const
39 // Check if we have the proper number of parameters
40 int numargs = numParams();
41 if( numargs != Num_ )
42 throw Error::NotEnoughParams( numargs, Num_ );
45 C& getObject()
47 PointerT Ptr;
48 typedef TypeConverter< obj_category, PointerT > tc;
49 tc::ConvertFromPython( m_pPyObj, Ptr );
50 return *Ptr;
53 template< typename category, typename T > bool getParam( const char* pName_, T& Dest_ )
55 typedef TypeConverter< category, T > tc;
56 PyObject* pParam = PyTuple_GET_ITEM( m_pArgs, m_paramindex );
58 if( !tc::CheckType_nothrow( pParam ) )
60 m_paramindex = 0;
61 return false;
64 tc::ConvertFromPython_nocheck( pParam, Dest_ );
65 ++m_paramindex;
66 return true;
69 template< typename category, typename T > void setReturnValue( const T& Value_ )
71 typedef TypeConverter< category, T > tc;
72 m_pResult = tc::ConvertToPython( Value_ );
75 // Cheapo ownership transfer
76 // This way the call context destructor knows that it should do a decref
77 // on the result object if it happens to be non-null.
78 PyObject* getResult()
80 PyObject* pRes = m_pResult;
81 m_pResult = NULL;
82 return pRes;
85 PyObject* m_pPyObj;
86 PyObject* m_pArgs;
87 int m_paramindex;
89 private:
90 PyObject* m_pResult;
93 template< class C, class CC > struct CtorWrapper
95 static PyObject* PyFunc( PyTypeObject* pSubType, PyObject* pArgs_, PyObject* )
97 PyObject* pPyObj = pSubType->tp_alloc( pSubType, 0 ); // Retarded C-style fake method call
99 try
101 CC context( pPyObj, pArgs_ );
102 if( !method_traits< C, typename class_traits< C >::ctor_tag >::
103 template CallWrapper< CC >::Call( context ) )
104 throw Error::NoOverloadFound();
106 return pPyObj;
108 catch( const Error::Base& error )
110 error.ConvertToPython();
111 Py_DECREF( pPyObj );
112 return 0;
117 template< class C, typename MtdTag, class CC > struct MethodWrapper
119 static PyObject* PyFunc( PyObject* pPyObj_, PyObject* pArgs_ )
123 CC context( pPyObj_, pArgs_ );
124 if( !method_traits< C, MtdTag >::template CallWrapper< CC >::Call( context ) )
125 throw Error::NoOverloadFound();
127 PyObject* pRes = context.getResult();
128 if( pRes )
129 return pRes;
131 Py_RETURN_NONE;
133 catch( const Error::Base& error )
135 error.ConvertToPython();
136 return 0;
142 #endif