| 1 |
/* |
|---|
| 2 |
Copyright 2006, 2007 Kirk McDonald |
|---|
| 3 |
|
|---|
| 4 |
Permission is hereby granted, free of charge, to any person obtaining a copy of |
|---|
| 5 |
this software and associated documentation files (the "Software"), to deal in |
|---|
| 6 |
the Software without restriction, including without limitation the rights to |
|---|
| 7 |
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
|---|
| 8 |
of the Software, and to permit persons to whom the Software is furnished to do |
|---|
| 9 |
so, subject to the following conditions: |
|---|
| 10 |
|
|---|
| 11 |
The above copyright notice and this permission notice shall be included in all |
|---|
| 12 |
copies or substantial portions of the Software. |
|---|
| 13 |
|
|---|
| 14 |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|---|
| 15 |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|---|
| 16 |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|---|
| 17 |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|---|
| 18 |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|---|
| 19 |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|---|
| 20 |
SOFTWARE. |
|---|
| 21 |
*/ |
|---|
| 22 |
module pyd.class_wrap; |
|---|
| 23 |
|
|---|
| 24 |
import python; |
|---|
| 25 |
|
|---|
| 26 |
import pyd.ctor_wrap; |
|---|
| 27 |
import pyd.def; |
|---|
| 28 |
import pyd.dg_convert; |
|---|
| 29 |
import pyd.exception; |
|---|
| 30 |
import pyd.func_wrap; |
|---|
| 31 |
version (Pyd_with_StackThreads) { |
|---|
| 32 |
import pyd.iteration; |
|---|
| 33 |
} |
|---|
| 34 |
import pyd.make_object; |
|---|
| 35 |
import pyd.make_wrapper; |
|---|
| 36 |
import pyd.op_wrap; |
|---|
| 37 |
import pyd.make_wrapper; |
|---|
| 38 |
import pyd.lib_abstract : |
|---|
| 39 |
symbolnameof, |
|---|
| 40 |
prettytypeof, |
|---|
| 41 |
toString, |
|---|
| 42 |
ParameterTypeTuple, |
|---|
| 43 |
ReturnType, |
|---|
| 44 |
minArgs, |
|---|
| 45 |
objToStr, |
|---|
| 46 |
ToString |
|---|
| 47 |
; |
|---|
| 48 |
|
|---|
| 49 |
//import meta.Default; |
|---|
| 50 |
|
|---|
| 51 |
PyTypeObject*[ClassInfo] wrapped_classes; |
|---|
| 52 |
template shim_class(T) { |
|---|
| 53 |
PyTypeObject* shim_class; |
|---|
| 54 |
} |
|---|
| 55 |
|
|---|
| 56 |
// This is split out in case I ever want to make a subtype of a wrapped class. |
|---|
| 57 |
template PydWrapObject_HEAD(T) { |
|---|
| 58 |
mixin PyObject_HEAD; |
|---|
| 59 |
T d_obj; |
|---|
| 60 |
} |
|---|
| 61 |
|
|---|
| 62 |
/// The class object, a subtype of PyObject |
|---|
| 63 |
template wrapped_class_object(T) { |
|---|
| 64 |
extern(C) |
|---|
| 65 |
struct wrapped_class_object { |
|---|
| 66 |
mixin PydWrapObject_HEAD!(T); |
|---|
| 67 |
} |
|---|
| 68 |
} |
|---|
| 69 |
|
|---|
| 70 |
/// |
|---|
| 71 |
template wrapped_class_type(T) { |
|---|
| 72 |
/// The type object, an instance of PyType_Type |
|---|
| 73 |
static PyTypeObject wrapped_class_type = { |
|---|
| 74 |
1, /*ob_refcnt*/ |
|---|
| 75 |
null, /*ob_type*/ |
|---|
| 76 |
0, /*ob_size*/ |
|---|
| 77 |
null, /*tp_name*/ |
|---|
| 78 |
0, /*tp_basicsize*/ |
|---|
| 79 |
0, /*tp_itemsize*/ |
|---|
| 80 |
&wrapped_methods!(T).wrapped_dealloc, /*tp_dealloc*/ |
|---|
| 81 |
null, /*tp_print*/ |
|---|
| 82 |
null, /*tp_getattr*/ |
|---|
| 83 |
null, /*tp_setattr*/ |
|---|
| 84 |
null, /*tp_compare*/ |
|---|
| 85 |
null, /*tp_repr*/ |
|---|
| 86 |
null, /*tp_as_number*/ |
|---|
| 87 |
null, /*tp_as_sequence*/ |
|---|
| 88 |
null, /*tp_as_mapping*/ |
|---|
| 89 |
null, /*tp_hash */ |
|---|
| 90 |
null, /*tp_call*/ |
|---|
| 91 |
null, /*tp_str*/ |
|---|
| 92 |
null, /*tp_getattro*/ |
|---|
| 93 |
null, /*tp_setattro*/ |
|---|
| 94 |
null, /*tp_as_buffer*/ |
|---|
| 95 |
0, /*tp_flags*/ |
|---|
| 96 |
null, /*tp_doc*/ |
|---|
| 97 |
null, /*tp_traverse*/ |
|---|
| 98 |
null, /*tp_clear*/ |
|---|
| 99 |
null, /*tp_richcompare*/ |
|---|
| 100 |
0, /*tp_weaklistoffset*/ |
|---|
| 101 |
null, /*tp_iter*/ |
|---|
| 102 |
null, /*tp_iternext*/ |
|---|
| 103 |
null, /*tp_methods*/ |
|---|
| 104 |
null, /*tp_members*/ |
|---|
| 105 |
null, /*tp_getset*/ |
|---|
| 106 |
null, /*tp_base*/ |
|---|
| 107 |
null, /*tp_dict*/ |
|---|
| 108 |
null, /*tp_descr_get*/ |
|---|
| 109 |
null, /*tp_descr_set*/ |
|---|
| 110 |
0, /*tp_dictoffset*/ |
|---|
| 111 |
null, /*tp_init*/ |
|---|
| 112 |
null, /*tp_alloc*/ |
|---|
| 113 |
&wrapped_methods!(T).wrapped_new, /*tp_new*/ |
|---|
| 114 |
null, /*tp_free*/ |
|---|
| 115 |
null, /*tp_is_gc*/ |
|---|
| 116 |
null, /*tp_bases*/ |
|---|
| 117 |
null, /*tp_mro*/ |
|---|
| 118 |
null, /*tp_cache*/ |
|---|
| 119 |
null, /*tp_subclasses*/ |
|---|
| 120 |
null, /*tp_weaklist*/ |
|---|
| 121 |
null, /*tp_del*/ |
|---|
| 122 |
}; |
|---|
| 123 |
} |
|---|
| 124 |
|
|---|
| 125 |
// A mappnig of all class references that are being held by Python. |
|---|
| 126 |
PyObject*[void*] wrapped_gc_objects; |
|---|
| 127 |
// A mapping of all GC references that are being held by Python. |
|---|
| 128 |
template wrapped_gc_references(dg_t) { |
|---|
| 129 |
PyObject*[dg_t] wrapped_gc_references; |
|---|
| 130 |
} |
|---|
| 131 |
|
|---|
| 132 |
/** |
|---|
| 133 |
* A useful check for whether a given class has been wrapped. Mainly used by |
|---|
| 134 |
* the conversion functions (see make_object.d), but possibly useful elsewhere. |
|---|
| 135 |
*/ |
|---|
| 136 |
template is_wrapped(T) { |
|---|
| 137 |
bool is_wrapped = false; |
|---|
| 138 |
} |
|---|
| 139 |
|
|---|
| 140 |
// The list of wrapped methods for this class. |
|---|
| 141 |
template wrapped_method_list(T) { |
|---|
| 142 |
PyMethodDef[] wrapped_method_list = [ |
|---|
| 143 |
{ null, null, 0, null } |
|---|
| 144 |
]; |
|---|
| 145 |
} |
|---|
| 146 |
|
|---|
| 147 |
// The list of wrapped properties for this class. |
|---|
| 148 |
template wrapped_prop_list(T) { |
|---|
| 149 |
static PyGetSetDef[] wrapped_prop_list = [ |
|---|
| 150 |
{ null, null, null, null, null } |
|---|
| 151 |
]; |
|---|
| 152 |
} |
|---|
| 153 |
|
|---|
| 154 |
////////////////////// |
|---|
| 155 |
// STANDARD METHODS // |
|---|
| 156 |
////////////////////// |
|---|
| 157 |
|
|---|
| 158 |
//import std.stdio; |
|---|
| 159 |
|
|---|
| 160 |
/// Various wrapped methods |
|---|
| 161 |
template wrapped_methods(T) { |
|---|
| 162 |
alias wrapped_class_object!(T) wrap_object; |
|---|
| 163 |
/// The generic "__new__" method |
|---|
| 164 |
extern(C) |
|---|
| 165 |
PyObject* wrapped_new(PyTypeObject* type, PyObject* args, PyObject* kwds) { |
|---|
| 166 |
return exception_catcher(delegate PyObject*() { |
|---|
| 167 |
wrap_object* self; |
|---|
| 168 |
|
|---|
| 169 |
self = cast(wrap_object*)type.tp_alloc(type, 0); |
|---|
| 170 |
if (self !is null) { |
|---|
| 171 |
self.d_obj = null; |
|---|
| 172 |
} |
|---|
| 173 |
|
|---|
| 174 |
return cast(PyObject*)self; |
|---|
| 175 |
}); |
|---|
| 176 |
} |
|---|
| 177 |
|
|---|
| 178 |
/// The generic dealloc method. |
|---|
| 179 |
extern(C) |
|---|
| 180 |
void wrapped_dealloc(PyObject* self) { |
|---|
| 181 |
exception_catcher(delegate void() { |
|---|
| 182 |
//writefln("wrapped_dealloc: T is %s", typeid(T)); |
|---|
| 183 |
WrapPyObject_SetObj!(T)(self, cast(T)null); |
|---|
| 184 |
self.ob_type.tp_free(self); |
|---|
| 185 |
}); |
|---|
| 186 |
} |
|---|
| 187 |
} |
|---|
| 188 |
|
|---|
| 189 |
template wrapped_repr(T, alias fn) { |
|---|
| 190 |
alias wrapped_class_object!(T) wrap_object; |
|---|
| 191 |
/// The default repr method calls the class's toString. |
|---|
| 192 |
extern(C) |
|---|
| 193 |
PyObject* repr(PyObject* self) { |
|---|
| 194 |
return exception_catcher(delegate PyObject*() { |
|---|
| 195 |
return method_wrap!(T, fn, char[] function()).func(self, null); |
|---|
| 196 |
}); |
|---|
| 197 |
} |
|---|
| 198 |
} |
|---|
| 199 |
|
|---|
| 200 |
// This template gets an alias to a property and derives the types of the |
|---|
| 201 |
// getter form and the setter form. It requires that the getter form return the |
|---|
| 202 |
// same type that the setter form accepts. |
|---|
| 203 |
template property_parts(alias p) { |
|---|
| 204 |
// This may be either the getter or the setter |
|---|
| 205 |
alias typeof(&p) p_t; |
|---|
| 206 |
alias ParameterTypeTuple!(p_t) Info; |
|---|
| 207 |
// This means it's the getter |
|---|
| 208 |
static if (Info.length == 0) { |
|---|
| 209 |
alias p_t getter_type; |
|---|
| 210 |
// The setter may return void, or it may return the newly set attribute. |
|---|
| 211 |
alias typeof(p(ReturnType!(p_t).init)) function(ReturnType!(p_t)) setter_type; |
|---|
| 212 |
// This means it's the setter |
|---|
| 213 |
} else { |
|---|
| 214 |
alias p_t setter_type; |
|---|
| 215 |
alias Info[0] function() getter_type; |
|---|
| 216 |
} |
|---|
| 217 |
} |
|---|
| 218 |
|
|---|
| 219 |
/// |
|---|
| 220 |
template wrapped_get(T, alias Fn) { |
|---|
| 221 |
/// A generic wrapper around a "getter" property. |
|---|
| 222 |
extern(C) |
|---|
| 223 |
PyObject* func(PyObject* self, void* closure) { |
|---|
| 224 |
// method_wrap already catches exceptions |
|---|
| 225 |
return method_wrap!(T, Fn, property_parts!(Fn).getter_type).func(self, null); |
|---|
| 226 |
} |
|---|
| 227 |
} |
|---|
| 228 |
|
|---|
| 229 |
/// |
|---|
| 230 |
template wrapped_set(T, alias Fn) { |
|---|
| 231 |
/// A generic wrapper around a "setter" property. |
|---|
| 232 |
extern(C) |
|---|
| 233 |
int func(PyObject* self, PyObject* value, void* closure) { |
|---|
| 234 |
PyObject* temp_tuple = PyTuple_New(1); |
|---|
| 235 |
if (temp_tuple is null) return -1; |
|---|
| 236 |
scope(exit) Py_DECREF(temp_tuple); |
|---|
| 237 |
Py_INCREF(value); |
|---|
| 238 |
PyTuple_SetItem(temp_tuple, 0, value); |
|---|
| 239 |
PyObject* res = method_wrap!(T, Fn, property_parts!(Fn).setter_type).func(self, temp_tuple); |
|---|
| 240 |
// If we get something back, we need to DECREF it. |
|---|
| 241 |
if (res) Py_DECREF(res); |
|---|
| 242 |
// If we don't, propagate the exception |
|---|
| 243 |
else return -1; |
|---|
| 244 |
// Otherwise, all is well. |
|---|
| 245 |
return 0; |
|---|
| 246 |
} |
|---|
| 247 |
} |
|---|
| 248 |
|
|---|
| 249 |
////////////////////////////// |
|---|
| 250 |
// CLASS WRAPPING INTERFACE // |
|---|
| 251 |
////////////////////////////// |
|---|
| 252 |
|
|---|
| 253 |
/+ |
|---|
| 254 |
/** |
|---|
| 255 |
* This struct wraps a D class. Its member functions are the primary way of |
|---|
| 256 |
* wrapping the specific parts of the class. |
|---|
| 257 |
*/ |
|---|
| 258 |
struct wrapped_class(T, char[] classname = symbolnameof!(T)) { |
|---|
| 259 |
static if (is(T == class)) pragma(msg, "wrapped_class: " ~ classname); |
|---|
| 260 |
static const char[] _name = classname; |
|---|
| 261 |
static bool _private = false; |
|---|
| 262 |
alias T wrapped_type; |
|---|
| 263 |
+/ |
|---|
| 264 |
|
|---|
| 265 |
//enum ParamType { Def, StaticDef, Property, Init, Parent, Hide, Iter, AltIter } |
|---|
| 266 |
struct DoNothing { |
|---|
| 267 |
static void call(T) () {} |
|---|
| 268 |
} |
|---|
| 269 |
/** |
|---|
| 270 |
Wraps a member function of the class. |
|---|
| 271 |
|
|---|
| 272 |
Params: |
|---|
| 273 |
fn = The member function to wrap. |
|---|
| 274 |
name = The name of the function as it will appear in Python. |
|---|
| 275 |
fn_t = The type of the function. It is only useful to specify this |
|---|
| 276 |
if more than one function has the same name as this one. |
|---|
| 277 |
*/ |
|---|
| 278 |
struct Def(alias fn) { |
|---|
| 279 |
mixin _Def!(fn, symbolnameof!(fn), typeof(&fn), ""); |
|---|
| 280 |
} |
|---|
| 281 |
struct Def(alias fn, string docstring) { |
|---|
| 282 |
mixin _Def!(fn, /*symbolnameof!(fn),*/ symbolnameof!(fn), typeof(&fn)/+, minArgs!(fn)+/, docstring); |
|---|
| 283 |
} |
|---|
| 284 |
struct Def(alias fn, string name, string docstring) { |
|---|
| 285 |
mixin _Def!(fn, /*symbolnameof!(fn),*/ name, typeof(&fn)/+, minArgs!(fn)+/, docstring); |
|---|
| 286 |
} |
|---|
| 287 |
struct Def(alias fn, string name, fn_t) { |
|---|
| 288 |
mixin _Def!(fn, /*symbolnameof!(fn),*/ name, fn_t/+, minArgs!(fn)+/, ""); |
|---|
| 289 |
} |
|---|
| 290 |
struct Def(alias fn, fn_t) { |
|---|
| 291 |
mixin _Def!(fn, /*symbolnameof!(fn),*/ symbolnameof!(fn), fn_t/+, minArgs!(fn)+/, ""); |
|---|
| 292 |
} |
|---|
| 293 |
struct Def(alias fn, fn_t, string docstring) { |
|---|
| 294 |
mixin _Def!(fn, /*symbolnameof!(fn),*/ symbolnameof!(fn), fn_t/+, minArgs!(fn)+/, docstring); |
|---|
| 295 |
} |
|---|
| 296 |
struct Def(alias fn, string name, fn_t, string docstring) { |
|---|
| 297 |
mixin _Def!(fn, /*symbolnameof!(fn),*/ name, fn_t/+, minArgs!(fn)+/, docstring); |
|---|
| 298 |
} |
|---|
| 299 |
/+ |
|---|
| 300 |
template Def(alias fn, string name, fn_t, uint MIN_ARGS=minArgs!(fn)/+, string docstring=""+/) { |
|---|
| 301 |
alias Def!(fn, /*symbolnameof!(fn),*/ name, fn_t, MIN_ARGS/+, docstring+/) Def; |
|---|
| 302 |
} |
|---|
| 303 |
+/ |
|---|
| 304 |
template _Def(alias fn, /*string _realname,*/ string name, fn_t/+, uint MIN_ARGS=minArgs!(fn)+/, string docstring) { |
|---|
| 305 |
//static const type = ParamType.Def; |
|---|
| 306 |
alias fn func; |
|---|
| 307 |
alias fn_t func_t; |
|---|
| 308 |
static const char[] realname = symbolnameof!(fn);//_realname; |
|---|
| 309 |
static const char[] funcname = name; |
|---|
| 310 |
static const uint min_args = minArgs!(fn); |
|---|
| 311 |
static const bool needs_shim = false; |
|---|
| 312 |
|
|---|
| 313 |
static void call(T) () { |
|---|
| 314 |
pragma(msg, "class.def: " ~ name); |
|---|
| 315 |
static PyMethodDef empty = { null, null, 0, null }; |
|---|
| 316 |
alias wrapped_method_list!(T) list; |
|---|
| 317 |
list[length-1].ml_name = (name ~ \0).ptr; |
|---|
| 318 |
list[length-1].ml_meth = &method_wrap!(T, fn, fn_t).func; |
|---|
| 319 |
list[length-1].ml_flags = METH_VARARGS; |
|---|
| 320 |
list[length-1].ml_doc = (docstring~\0).ptr; |
|---|
| 321 |
list ~= empty; |
|---|
| 322 |
// It's possible that appending the empty item invalidated the |
|---|
| 323 |
// pointer in the type struct, so we renew it here. |
|---|
| 324 |
wrapped_class_type!(T).tp_methods = list.ptr; |
|---|
| 325 |
} |
|---|
| 326 |
template shim(uint i) { |
|---|
| 327 |
const char[] shim = |
|---|
| 328 |
" alias Params["~ToString!(i)~"] __pyd_p"~ToString!(i)~";\n" |
|---|
| 329 |
" ReturnType!(__pyd_p"~ToString!(i)~".func_t) "~realname~"(ParameterTypeTuple!(__pyd_p"~ToString!(i)~".func_t) t) {\n" |
|---|
| 330 |
" return __pyd_get_overload!(\""~realname~"\", __pyd_p"~ToString!(i)~".func_t).func(\""~name~"\", t);\n" |
|---|
| 331 |
" }\n"; |
|---|
| 332 |
} |
|---|
| 333 |
} |
|---|
| 334 |
|
|---|
| 335 |
/** |
|---|
| 336 |
Wraps a static member function of the class. Identical to pyd.def.def |
|---|
| 337 |
*/ |
|---|
| 338 |
struct StaticDef(alias fn) { |
|---|
| 339 |
mixin _StaticDef!(fn,/+ symbolnameof!(fn),+/ symbolnameof!(fn), typeof(&fn), minArgs!(fn), ""); |
|---|
| 340 |
} |
|---|
| 341 |
struct StaticDef(alias fn, string docstring) { |
|---|
| 342 |
mixin _StaticDef!(fn,/+ symbolnameof!(fn),+/ symbolnameof!(fn), typeof(&fn), minArgs!(fn), docstring); |
|---|
| 343 |
} |
|---|
| 344 |
struct StaticDef(alias _fn, string name, string docstring) { |
|---|
| 345 |
mixin _StaticDef!(fn,/+ symbolnameof!(fn),+/ name, typeof(&fn), minArgs!(fn), docstring); |
|---|
| 346 |
} |
|---|
| 347 |
struct StaticDef(alias _fn, string name, fn_t, string docstring) { |
|---|
| 348 |
mixin _StaticDef!(fn,/+ symbolnameof!(fn),+/ name, fn_t, minArgs!(fn), docstring); |
|---|
| 349 |
} |
|---|
| 350 |
struct StaticDef(alias _fn, fn_t) { |
|---|
| 351 |
mixin _StaticDef!(fn,/+ symbolnameof!(fn),+/ symbolnameof!(fn), fn_t, minArgs!(fn), ""); |
|---|
| 352 |
} |
|---|
| 353 |
struct StaticDef(alias _fn, fn_t, string docstring) { |
|---|
| 354 |
mixin _StaticDef!(fn,/+ symbolnameof!(fn),+/ symbolnameof!(fn), fn_t, minArgs!(fn), docstring); |
|---|
| 355 |
} |
|---|
| 356 |
struct StaticDef(alias _fn, string name, fn_t) { |
|---|
| 357 |
mixin _StaticDef!(fn,/+ symbolnameof!(fn),+/ name, fn_t, minArgs!(fn), ""); |
|---|
| 358 |
} |
|---|
| 359 |
struct StaticDef(alias _fn, string name, fn_t, uint MIN_ARGS) { |
|---|
| 360 |
mixin _StaticDef!(fn,/+ symbolnameof!(fn),+/ name, fn_t, MIN_ARGS, ""); |
|---|
| 361 |
} |
|---|
| 362 |
struct StaticDef(alias _fn, string name, fn_t, uint MIN_ARGS, string docstring) { |
|---|
| 363 |
mixin _StaticDef!(fn,/+ symbolnameof!(fn),+/ name, fn_t, MIN_ARGS, docstring); |
|---|
| 364 |
} |
|---|
| 365 |
template _StaticDef(alias fn,/+ string _realname,+/ string name, fn_t, uint MIN_ARGS, string docstring) { |
|---|
| 366 |
//static const type = ParamType.StaticDef; |
|---|
| 367 |
alias fn func; |
|---|
| 368 |
alias fn_t func_t; |
|---|
| 369 |
static const char[] funcname = name; |
|---|
| 370 |
static const uint min_args = MIN_ARGS; |
|---|
| 371 |
static const bool needs_shim = false; |
|---|
| 372 |
static void call(T) () { |
|---|
| 373 |
pragma(msg, "class.static_def: " ~ name); |
|---|
| 374 |
static PyMethodDef empty = { null, null, 0, null }; |
|---|
| 375 |
alias wrapped_method_list!(T) list; |
|---|
| 376 |
list[length-1].ml_name = (name ~ \0).ptr; |
|---|
| 377 |
list[length-1].ml_meth = &function_wrap!(fn, MIN_ARGS, fn_t).func; |
|---|
| 378 |
list[length-1].ml_flags = METH_VARARGS | METH_STATIC; |
|---|
| 379 |
list[length-1].ml_doc = (docstring~\0).ptr; |
|---|
| 380 |
list ~= empty; |
|---|
| 381 |
wrapped_class_type!(T).tp_methods = list; |
|---|
| 382 |
} |
|---|
| 383 |
template shim(uint i) { |
|---|
| 384 |
const char[] shim = ""; |
|---|
| 385 |
} |
|---|
| 386 |
} |
|---|
| 387 |
|
|---|
| 388 |
/** |
|---|
| 389 |
Wraps a property of the class. |
|---|
| 390 |
|
|---|
| 391 |
Params: |
|---|
| 392 |
fn = The property to wrap. |
|---|
| 393 |
name = The name of the property as it will appear in Python. |
|---|
| 394 |
RO = Whether this is a read-only property. |
|---|
| 395 |
*/ |
|---|
| 396 |
//template Property(alias fn, char[] name = symbolnameof!(fn), bool RO=false, char[] docstring = "") { |
|---|
| 397 |
// alias Property!(fn, symbolnameof!(fn), name, RO, docstring) Property; |
|---|
| 398 |
//} |
|---|
| 399 |
struct Property(alias fn) { |
|---|
| 400 |
mixin _Property!(fn, symbolnameof!(fn), symbolnameof!(fn), false, ""); |
|---|
| 401 |
} |
|---|
| 402 |
struct Property(alias fn, string docstring) { |
|---|
| 403 |
mixin _Property!(fn, symbolnameof!(fn), symbolnameof!(fn), false, docstring); |
|---|
| 404 |
} |
|---|
| 405 |
struct Property(alias fn, string name, string docstring) { |
|---|
| 406 |
mixin _Property!(fn, symbolnameof!(fn), name, false, docstring); |
|---|
| 407 |
} |
|---|
| 408 |
struct Property(alias fn, string name, bool RO) { |
|---|
| 409 |
mixin _Property!(fn, symbolnameof!(fn), name, RO, ""); |
|---|
| 410 |
} |
|---|
| 411 |
struct Property(alias fn, string name, bool RO, string docstring) { |
|---|
| 412 |
mixin _Property!(fn, symbolnameof!(fn), name, RO, docstring); |
|---|
| 413 |
} |
|---|
| 414 |
struct Property(alias fn, bool RO) { |
|---|
| 415 |
mixin _Property!(fn, symbolnameof!(fn), symbolnameof!(fn), RO, ""); |
|---|
| 416 |
} |
|---|
| 417 |
struct Property(alias fn, bool RO, string docstring) { |
|---|
| 418 |
mixin _Property!(fn, symbolnameof!(fn), symbolnameof!(fn), RO, docstring); |
|---|
| 419 |
} |
|---|
| 420 |
template _Property(alias fn, string _realname, string name, bool RO, string docstring) { |
|---|
| 421 |
alias property_parts!(fn).getter_type get_t; |
|---|
| 422 |
alias property_parts!(fn).setter_type set_t; |
|---|
| 423 |
static const char[] realname = _realname; |
|---|
| 424 |
static const char[] funcname = name; |
|---|
| 425 |
static const bool readonly = RO; |
|---|
| 426 |
static const bool needs_shim = false; |
|---|
| 427 |
static void call(T) () { |
|---|
| 428 |
pragma(msg, "class.prop: " ~ name); |
|---|
| 429 |
static PyGetSetDef empty = { null, null, null, null, null }; |
|---|
| 430 |
wrapped_prop_list!(T)[length-1].name = (name ~ \0).ptr; |
|---|
| 431 |
wrapped_prop_list!(T)[length-1].get = |
|---|
| 432 |
&wrapped_get!(T, fn).func; |
|---|
| 433 |
static if (!RO) { |
|---|
| 434 |
wrapped_prop_list!(T)[length-1].set = |
|---|
| 435 |
&wrapped_set!(T, fn).func; |
|---|
| 436 |
} |
|---|
| 437 |
wrapped_prop_list!(T)[length-1].doc = (docstring~\0).ptr; |
|---|
| 438 |
wrapped_prop_list!(T)[length-1].closure = null; |
|---|
| 439 |
wrapped_prop_list!(T) ~= empty; |
|---|
| 440 |
// It's possible that appending the empty item invalidated the |
|---|
| 441 |
// pointer in the type struct, so we renew it here. |
|---|
| 442 |
wrapped_class_type!(T).tp_getset = |
|---|
| 443 |
wrapped_prop_list!(T).ptr; |
|---|
| 444 |
} |
|---|
| 445 |
template shim_setter(uint i) { |
|---|
| 446 |
static if (RO) { |
|---|
| 447 |
const char[] shim_setter = ""; |
|---|
| 448 |
} else { |
|---|
| 449 |
const char[] shim_setter = |
|---|
| 450 |
" ReturnType!(__pyd_p"~ToString!(i)~".set_t) "~_realname~"(ParameterTypeTuple!(__pyd_p"~ToString!(i)~".set_t) t) {\n" |
|---|
| 451 |
" return __pyd_get_overload!(\""~_realname~"\", __pyd_p"~ToString!(i)~".set_t).func(\""~name~"\", t);\n" |
|---|
| 452 |
" }\n"; |
|---|
| 453 |
} |
|---|
| 454 |
} |
|---|
| 455 |
template shim(uint i) { |
|---|
| 456 |
const char[] shim = |
|---|
| 457 |
" alias Params["~ToString!(i)~"] __pyd_p"~ToString!(i)~";\n" |
|---|
| 458 |
" ReturnType!(__pyd_p"~ToString!(i)~".get_t) "~_realname~"() {\n" |
|---|
| 459 |
" return __pyd_get_overload!(\""~_realname~"\", __pyd_p"~ToString!(i)~".get_t).func(\""~name~"\");\n" |
|---|
| 460 |
" }\n" ~ |
|---|
| 461 |
shim_setter!(i); |
|---|
| 462 |
} |
|---|
| 463 |
} |
|---|
| 464 |
|
|---|
| 465 |
/** |
|---|
| 466 |
Wraps a method as the class's __repr__ in Python. |
|---|
| 467 |
*/ |
|---|
| 468 |
struct Repr(alias fn) { |
|---|
| 469 |
static const bool needs_shim = false; |
|---|
| 470 |
static void call(T)() { |
|---|
| 471 |
alias wrapped_class_type!(T) type; |
|---|
| 472 |
type.tp_repr = &wrapped_repr!(T, fn).repr; |
|---|
| 473 |
} |
|---|
| 474 |
template shim(uint i) { |
|---|
| 475 |
const char[] shim = ""; |
|---|
| 476 |
} |
|---|
| 477 |
} |
|---|
| 478 |
|
|---|
| 479 |
/** |
|---|
| 480 |
Wraps the constructors of the class. |
|---|
| 481 |
|
|---|
| 482 |
This template takes a series of specializations of the ctor template |
|---|
| 483 |
(see ctor_wrap.d), each of which describes a different constructor |
|---|
| 484 |
that the class supports. The default constructor need not be |
|---|
| 485 |
specified, and will always be available if the class supports it. |
|---|
| 486 |
|
|---|
| 487 |
Bugs: |
|---|
| 488 |
This currently does not support having multiple constructors with |
|---|
| 489 |
the same number of arguments. |
|---|
| 490 |
*/ |
|---|
| 491 |
struct Init(C ...) { |
|---|
| 492 |
alias C ctors; |
|---|
| 493 |
static const bool needs_shim = true; |
|---|
| 494 |
template call(T, shim) { |
|---|
| 495 |
//mixin wrapped_ctors!(param.ctors) Ctors; |
|---|
| 496 |
static void call() { |
|---|
| 497 |
wrapped_class_type!(T).tp_init = |
|---|
| 498 |
//&Ctors.init_func; |
|---|
| 499 |
&wrapped_ctors!(shim, C).init_func; |
|---|
| 500 |
} |
|---|
| 501 |
} |
|---|
| 502 |
template shim_impl(uint i, uint c=0) { |
|---|
| 503 |
static if (c < ctors.length) { |
|---|
| 504 |
const char[] shim_impl = |
|---|
| 505 |
" this(ParameterTypeTuple!(__pyd_c"~ToString!(i)~"["~ToString!(c)~"]) t) {\n" |
|---|
| 506 |
" super(t);\n" |
|---|
| 507 |
" }\n" ~ shim_impl!(i, c+1); |
|---|
| 508 |
} else { |
|---|
| 509 |
const char[] shim_impl = |
|---|
| 510 |
" static if (is(typeof(new T))) {\n" |
|---|
| 511 |
" this() { super(); }\n" |
|---|
| 512 |
" }\n"; |
|---|
| 513 |
} |
|---|
| 514 |
} |
|---|
| 515 |
template shim(uint i) { |
|---|
| 516 |
const char[] shim = |
|---|
| 517 |
" alias Params["~ToString!(i)~"] __pyd_p"~ToString!(i)~";\n" |
|---|
| 518 |
" alias __pyd_p"~ToString!(i)~".ctors __pyd_c"~ToString!(i)~";\n"~ |
|---|
| 519 |
shim_impl!(i); |
|---|
| 520 |
} |
|---|
| 521 |
} |
|---|
| 522 |
|
|---|
| 523 |
// Iteration wrapping support requires StackThreads |
|---|
| 524 |
version(Pyd_with_StackThreads) { |
|---|
| 525 |
|
|---|
| 526 |
/** |
|---|
| 527 |
Allows selection of alternate opApply overloads. iter_t should be |
|---|
| 528 |
the type of the delegate in the opApply function that the user wants |
|---|
| 529 |
to be the default. |
|---|
| 530 |
*/ |
|---|
| 531 |
struct Iter(iter_t) { |
|---|
| 532 |
static const bool needs_shim = false; |
|---|
| 533 |
alias iter_t iterator_t; |
|---|
| 534 |
static void call(T) () { |
|---|
| 535 |
PydStackContext_Ready(); |
|---|
| 536 |
// This strange bit of hackery is needed since we operate on pointer- |
|---|
| 537 |
// to-struct types, rather than just struct types. |
|---|
| 538 |
static if (is(T S : S*) && is(S == struct)) { |
|---|
| 539 |
wrapped_class_type!(T).tp_iter = &wrapped_iter!(T, S.opApply, int function(iter_t)).iter; |
|---|
| 540 |
} else { |
|---|
| 541 |
wrapped_class_type!(T).tp_iter = &wrapped_iter!(T, T.opApply, int function(iter_t)).iter; |
|---|
| 542 |
} |
|---|
| 543 |
} |
|---|
| 544 |
} |
|---|
| 545 |
|
|---|
| 546 |
/** |
|---|
| 547 |
Exposes alternate iteration methods, originally intended for use with |
|---|
| 548 |
D's delegate-as-iterator features, as methods returning a Python |
|---|
| 549 |
iterator. |
|---|
| 550 |
*/ |
|---|
| 551 |
struct AltIter(alias fn, string name = symbolnameof!(fn), iter_t = ParameterTypeTuple!(fn)[0]) { |
|---|
|
|---|