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 23 /++ 24 This module contains some useful type conversion functions. The two 25 most interesting operations here are python_to_d and d_to_python. 26 27 Additionally, the py function is provided as a convenience to directly 28 convert a D object into an instance of PydObject. 29 30 To convert a PydObject to a D type, use PydObject.to_d. 31 +/ 32 module pyd.make_object; 33 34 import deimos.python.Python; 35 36 import std.array; 37 import std.algorithm; 38 import std.complex; 39 import std.typetuple; 40 import std.bigint; 41 import std.traits; 42 import std.typecons; 43 import std.conv; 44 import std.range; 45 import std.stdio; 46 47 import core.stdc.string : memcpy, strlen; 48 49 import pyd.references; 50 import pyd.pydobject; 51 import pyd.class_wrap; 52 import pyd.struct_wrap; 53 import pyd.func_wrap; 54 import pyd.def; 55 import pyd.exception; 56 57 58 shared static this() { 59 init_rangewrapper(); 60 } 61 62 void init_rangewrapper() { 63 version(PydPythonExtension) { 64 on_py_init({ 65 wrap_struct!(RangeWrapper, 66 Def!(RangeWrapper.iter, PyName!"__iter__"), 67 Def!(RangeWrapper.next))(); 68 rangeWrapperInited = true; 69 }, PyInitOrdering.After); 70 }else{ 71 on_py_init( { 72 add_module!(ModuleName!"pyd")(); 73 }); 74 on_py_init( { 75 wrap_struct!(RangeWrapper, 76 ModuleName!"pyd", 77 Def!(RangeWrapper.iter, PyName!"__iter__"), 78 Def!(RangeWrapper.next))(); 79 rangeWrapperInited = true; 80 }, PyInitOrdering.After); 81 } 82 } 83 84 bool rangeWrapperInited = false; 85 86 class to_conversion_wrapper(dg_t) { 87 alias ParameterTypeTuple!(dg_t)[0] T; 88 alias ReturnType!(dg_t) Intermediate; 89 dg_t dg; 90 this(dg_t fn) { dg = fn; } 91 PyObject* opCall(T t) { 92 static if (is(Intermediate == PyObject*)) { 93 return dg(t); 94 } else { 95 return d_to_python(dg(t)); 96 } 97 } 98 } 99 class from_conversion_wrapper(dg_t) { 100 alias ParameterTypeTuple!(dg_t)[0] Intermediate; 101 alias ReturnType!(dg_t) T; 102 dg_t dg; 103 this(dg_t fn) { dg = fn; } 104 T opCall(PyObject* o) { 105 static if (is(Intermediate == PyObject*)) { 106 return dg(o); 107 } else { 108 return dg(python_to_d!(Intermediate)(o)); 109 } 110 } 111 } 112 113 template to_converter_registry(From) { 114 PyObject* delegate(From) dg=null; 115 } 116 template from_converter_registry(To) { 117 To delegate(PyObject*) dg=null; 118 } 119 120 /** 121 Extend pyd's conversion mechanism. Will be used by d_to_python only if d_to_python cannot 122 convert its argument by regular means. 123 124 Params: 125 dg = A callable which takes a D type and returns a PyObject*, or any 126 type convertible by d_to_python. 127 */ 128 void ex_d_to_python(dg_t) (dg_t dg) { 129 static if (is(dg_t == delegate) && is(ReturnType!(dg_t) == PyObject*)) { 130 to_converter_registry!(ParameterTypeTuple!(dg_t)[0]).dg = dg; 131 } else { 132 auto o = new to_conversion_wrapper!(dg_t)(dg); 133 to_converter_registry!(typeof(o).T).dg = &o.opCall; 134 } 135 } 136 137 /** 138 Extend pyd's conversion mechanims. Will be used by python_to_d only if python_to_d 139 cannot convert its argument by regular means. 140 141 Params: 142 dg = A callable which takes a PyObject*, or any type convertible by python_to_d, 143 and returns a D type. 144 */ 145 void ex_python_to_d(dg_t) (dg_t dg) { 146 static if (is(dg_t == delegate) && is(ParameterTypeTuple!(dg_t)[0] == PyObject*)) { 147 from_converter_registry!(ReturnType!(dg_t)).dg = dg; 148 } else { 149 auto o = new from_conversion_wrapper!(dg_t)(dg); 150 from_converter_registry!(typeof(o).T).dg = &o.opCall; 151 } 152 } 153 154 /** 155 * Returns a new (owned) reference to a Python object based on the passed 156 * argument. If the passed argument is a PyObject*, this "steals" the 157 * reference. (In other words, it returns the PyObject* without changing its 158 * reference count.) If the passed argument is a PydObject, this returns a new 159 * reference to whatever the PydObject holds a reference to. 160 * 161 * If the passed argument can't be converted to a PyObject, a Python 162 * RuntimeError will be raised and this function will return null. 163 */ 164 PyObject* d_to_python(T) (T t) { 165 static if (!is(T == PyObject*) && is(typeof(t is null)) && 166 !isAssociativeArray!T && !isArray!T) { 167 if (t is null) { 168 return Py_INCREF(Py_None()); 169 } 170 } 171 static if (isBoolean!T) { 172 return Py_INCREF(t ? Py_True : Py_False); 173 } else static if(isIntegral!T) { 174 static if(isUnsigned!T) { 175 return PyLong_FromUnsignedLongLong(t); 176 }else static if(isSigned!T) { 177 return PyLong_FromLongLong(t); 178 } 179 } else static if (isFloatingPoint!T) { 180 return PyFloat_FromDouble(t); 181 } else static if( isTuple!T) { 182 return d_tuple_to_python!T(t); 183 } else static if (is(Unqual!T _unused : Complex!F, F)) { 184 return PyComplex_FromDoubles(t.re, t.im); 185 } else static if(is(T == std.bigint.BigInt)) { 186 return d_bigint_to_python(t); 187 } else static if(is(Unqual!T _unused : PydInputRange!E, E)) { 188 return Py_INCREF(t.ptr); 189 } else static if(isSomeString!T) { 190 return d_string_to_python(t); 191 } else static if (isArray!(T)) { 192 return d_array_to_python(t); 193 } else static if (isAssociativeArray!(T)) { 194 return d_aarray_to_python(t); 195 } else static if (isDelegate!T || isFunctionPointer!T) { 196 PydWrappedFunc_Ready!(T)(); 197 return wrap_d_object(t); 198 } else static if (is(T : PydObject)) { 199 return Py_INCREF(t.ptr()); 200 } else static if (is(T : PyObject*)) { 201 // The function expects to be passed a borrowed reference and return an 202 // owned reference. Thus, if passed a PyObject*, this will increment the 203 // reference count. 204 Py_XINCREF(t); 205 return t; 206 } else static if (is(T == class)) { 207 // Convert wrapped type to a PyObject* 208 alias Unqual!T Tu; 209 // But only if it actually is a wrapped type. :-) 210 PyTypeObject** type = Tu.classinfo in wrapped_classes; 211 if (type) { 212 return wrap_d_object(t, *type); 213 } 214 return d_to_python_try_extends(t); 215 // If it's not a wrapped type, fall through to the exception. 216 // If converting a struct by value, create a copy and wrap that 217 } else static if (is(T == struct) && 218 !is(T == RangeWrapper) && 219 isInputRange!T) { 220 if (to_converter_registry!(T).dg) { 221 return d_to_python_try_extends(t); 222 }else static if(__traits(compiles, wrap_range(t))) { 223 assert(is_wrapped!(RangeWrapper*)); 224 return d_to_python(wrap_range(t)); 225 } 226 } else static if (is(T == struct)) { 227 alias Unqual!T Tu; 228 if (is_wrapped!(Tu*)) { 229 Tu* temp = new Tu; 230 *temp = cast(Tu) t; 231 return wrap_d_object(cast(T*)temp); 232 } 233 return d_to_python_try_extends(t); 234 // If converting a struct by reference, wrap the thing directly 235 } else static if (is(typeof(*t) == struct)) { 236 alias Unqual!T Tu; 237 if (is_wrapped!(Tu)) { 238 if (t is null) { 239 return Py_INCREF(Py_None()); 240 } 241 return wrap_d_object(t); 242 } 243 return d_to_python_try_extends(t); 244 } 245 246 assert(0); 247 } 248 249 PyObject* d_to_python_try_extends(T) (T t) { 250 if (to_converter_registry!(T).dg) { 251 return to_converter_registry!(T).dg(t); 252 } 253 PyErr_SetString(PyExc_RuntimeError, ("D conversion function d_to_python failed with type " ~ typeid(T).toString()).ptr); 254 return null; 255 } 256 257 PyObject* d_tuple_to_python(T) (T t) if (isTuple!T) { 258 T.Types tuple; 259 foreach(i, _t; T.Types) { 260 tuple[i] = t[i]; 261 } 262 return PyTuple_FromItems(tuple); 263 } 264 265 PyObject* d_bigint_to_python(BigInt t) { 266 import std.string: format; 267 string num_str = format("%s\0",t); 268 return PyLong_FromString(num_str.dup.ptr, null, 10); 269 } 270 271 PyObject* d_string_to_python(T)(T t) if(isSomeString!T) { 272 alias Unqual!(typeof(T.init[0])) C; 273 static if(is(C == char)) { 274 return PyUnicode_DecodeUTF8(t.ptr, cast(Py_ssize_t) t.length, null); 275 }else static if(is(C == wchar)) { 276 return PyUnicode_DecodeUTF16(cast(char*) t.ptr, 277 cast(Py_ssize_t)(2*t.length), null, null); 278 }else static if(is(C == dchar)) { 279 version(Python_2_6_Or_Later) { 280 return PyUnicode_DecodeUTF32(cast(char*) t.ptr, 281 cast(Py_ssize_t)(4*t.length), null, null); 282 }else{ 283 return d_to_python(to!string(t)); 284 } 285 }else static assert(false, "waht is this T? " ~ T.stringof); 286 } 287 288 PyObject* d_array_to_python(T)(T t) if(isArray!T) { 289 // Converts any array (static or dynamic) to a Python list 290 PyObject* lst = PyList_New(cast(Py_ssize_t) t.length); 291 PyObject* temp; 292 if (lst is null) return null; 293 for(int i=0; i<t.length; ++i) { 294 temp = d_to_python(t[i]); 295 if (temp is null) { 296 Py_DECREF(lst); 297 return null; 298 } 299 // Steals the reference to temp 300 PyList_SET_ITEM(lst, cast(Py_ssize_t) i, temp); 301 } 302 return lst; 303 } 304 305 PyObject* d_aarray_to_python(T)(T t) if(isAssociativeArray!T) { 306 // Converts any associative array to a Python dict 307 PyObject* dict = PyDict_New(); 308 PyObject* ktemp, vtemp; 309 int result; 310 if (dict is null) return null; 311 foreach(k, v; t) { 312 ktemp = d_to_python(k); 313 vtemp = d_to_python(v); 314 if (ktemp is null || vtemp is null) { 315 if (ktemp !is null) Py_DECREF(ktemp); 316 if (vtemp !is null) Py_DECREF(vtemp); 317 Py_DECREF(dict); 318 return null; 319 } 320 result = PyDict_SetItem(dict, ktemp, vtemp); 321 Py_DECREF(ktemp); 322 Py_DECREF(vtemp); 323 if (result == -1) { 324 Py_DECREF(dict); 325 return null; 326 } 327 } 328 return dict; 329 } 330 331 T python_to_aarray(T)(PyObject* py) if(isAssociativeArray!T) { 332 PyObject* keys = null; 333 if(PyDict_Check(py)) { 334 keys = PyDict_Keys(py); 335 }else if(PyMapping_Keys(py)) { 336 keys = PyMapping_Keys(py); 337 }else{ 338 could_not_convert!(T)(py); 339 assert(0); 340 } 341 PyObject* iterator = PyObject_GetIter(keys); 342 T result; 343 PyObject* key; 344 while ((key=PyIter_Next(iterator)) !is null) { 345 PyObject* value = PyObject_GetItem(py, key); 346 auto d_key = python_to_d!(KeyType!T)(key); 347 auto d_value = python_to_d!(ValueType!T)(value); 348 result[d_key] = d_value; 349 Py_DECREF(key); 350 Py_DECREF(value); 351 } 352 Py_DECREF(iterator); 353 return result; 354 } 355 356 /** 357 * Helper function for creating a PyTuple from a series of D items. 358 */ 359 PyObject* PyTuple_FromItems(T ...)(T t) { 360 PyObject* tuple = PyTuple_New(t.length); 361 PyObject* temp; 362 if (tuple is null) return null; 363 foreach(i, arg; t) { 364 temp = d_to_python(arg); 365 if (temp is null) { 366 Py_DECREF(tuple); 367 return null; 368 } 369 PyTuple_SetItem(tuple, i, temp); 370 } 371 return tuple; 372 } 373 374 /** 375 * Constructs an object based on the type of the argument passed in. 376 * 377 * For example, calling py(10) would return a PydObject holding the value 10. 378 * 379 * Calling this with a PydObject will return back a reference to the very same 380 * PydObject. 381 */ 382 PydObject py(T) (T t) { 383 static if(is(T : PydObject)) { 384 return t; 385 } else { 386 return new PydObject(d_to_python(t)); 387 } 388 } 389 390 /** 391 * An exception class used by python_to_d. 392 */ 393 class PydConversionException : Exception { 394 this(string msg, string file = __FILE__, size_t line = __LINE__) { 395 super(msg, file, line); 396 } 397 } 398 399 /** 400 * This converts a PyObject* to a D type. The template argument is the type to 401 * convert to. The function argument is the PyObject* to convert. For instance: 402 * 403 *$(D_CODE PyObject* i = PyInt_FromLong(20); 404 *int n = _python_to_d!(int)(i); 405 *assert(n == 20);) 406 * 407 * This throws a PydConversionException if the PyObject can't be converted to 408 * the given D type. 409 */ 410 T python_to_d(T) (PyObject* o) { 411 // This ordering is somewhat important. The checks for Tuple and Complex 412 // must be before the check for general structs. 413 version(PydPythonExtension) { 414 // druntime doesn't run module ctors :( 415 if(!rangeWrapperInited) { 416 init_rangewrapper(); 417 } 418 } 419 420 static if (is(PyObject* : T)) { 421 return o; 422 } else static if (is(PydObject : T)) { 423 return new PydObject(borrowed(o)); 424 } else static if (is(T == void)) { 425 if (o != cast(PyObject*) Py_None()) could_not_convert!(T)(o); 426 return; 427 } else static if (isTuple!T) { 428 if(PyTuple_Check(o)) { 429 return python_to_d_tuple!T(o); 430 } 431 return python_to_d_try_extends!T(o); 432 } else static if (is(Unqual!T _unused : Complex!F, F)) { 433 if (PyComplex_Check(o) || isNumpyComplexNumber(o)) { 434 return python_to_d_complex!T(o); 435 } 436 return python_to_d_try_extends!T(o); 437 } else static if(is(Unqual!T == std.bigint.BigInt)) { 438 if (isPyNumber(o)) { 439 return python_to_d_bigint!T(o); 440 } 441 if (isNumpyNumber(o)) { 442 auto i = to_python_int(o); 443 return python_to_d_bigint!T(i); 444 } 445 return python_to_d_try_extends!T(o); 446 } else static if(is(Unqual!T _unused : PydInputRange!E, E)) { 447 return cast(T) PydInputRange!E(borrowed(o)); 448 } else static if (is(T == class)) { 449 // We can only convert to a class if it has been wrapped, and of course 450 // we can only convert the object if it is the wrapped type. 451 if ( 452 is_wrapped!(T) && 453 PyObject_IsInstance(o, cast(PyObject*)&PydTypeObject!(T)) ) 454 { 455 if ( get_d_reference!T(o) !is null) { 456 return get_d_reference!(T)(o); 457 } 458 } 459 return python_to_d_try_extends!T(o); 460 } else static if (is(T == struct)) { // struct by value 461 // struct is wrapped 462 if (is_wrapped!(T*) && PyObject_TypeCheck(o, &PydTypeObject!(T*))) { 463 return *get_d_reference!(T*)(o); 464 } 465 // or struct is wrapped range 466 if(PyObject_IsInstance(o, 467 cast(PyObject*)&PydTypeObject!(RangeWrapper*))) { 468 RangeWrapper* wrapper = get_d_reference!(RangeWrapper*)(o); 469 if(typeid(T) != wrapper.tid) { 470 could_not_convert!T(o, format("typeid mismatch: %s vs %s", 471 wrapper.tid, typeid(T))); 472 } 473 T t = *cast(T*) wrapper.range; 474 return t; 475 } 476 return python_to_d_try_extends!T(o); 477 } else static if (isPointer!T && is(pointerTarget!T == struct)) { 478 // pointer to struct 479 if (is_wrapped!(T) && PyObject_TypeCheck(o, &PydTypeObject!(T))) { 480 return get_d_reference!(T)(o); 481 } 482 return python_to_d_try_extends!T(o); 483 } else static if (is(T == delegate)) { 484 // Get the original wrapped delegate out if this is a wrapped delegate 485 if (is_wrapped!(T) && PyObject_TypeCheck(o, &PydTypeObject!(T))) { 486 return get_d_reference!(T)(o); 487 // Otherwise, wrap the PyCallable with a delegate 488 } else if (PyCallable_Check(o)) { 489 return PydCallable_AsDelegate!(T)(o); 490 } 491 return python_to_d_try_extends!T(o); 492 } else static if (isDelegate!T || isFunctionPointer!T) { 493 // We can only make it a function pointer if we originally wrapped a 494 // function pointer. 495 if (is_wrapped!(T) && PyObject_TypeCheck(o, &PydTypeObject!(T))) { 496 return get_d_reference!(T)(o); 497 } 498 return python_to_d_try_extends!T(o); 499 } else static if (isSomeString!T) { 500 return python_to_d_string!T(o); 501 } else static if (isArray!T || IsStaticArrayPointer!T) { 502 static if(isPointer!T) { 503 alias Unqual!(ElementType!(pointerTarget!T)) E; 504 }else { 505 alias Unqual!(ElementType!T) E; 506 } 507 version(Python_2_6_Or_Later) { 508 if(PyObject_CheckBuffer(o)) { 509 return python_buffer_to_d!(T)(o); 510 } 511 } 512 if(o.ob_type is array_array_Type) { 513 return python_array_array_to_d!T(o); 514 }else { 515 return python_iter_to_d!T(o); 516 } 517 } else static if (isAssociativeArray!T) { 518 return python_to_aarray!T(o); 519 } else static if (isFloatingPoint!T) { 520 if (isPyNumber(o) || isNumpyNumber(o)) { 521 double res = PyFloat_AsDouble(o); 522 return cast(T) res; 523 } 524 return python_to_d_try_extends!T(o); 525 } else static if(isIntegral!T) { 526 if (isNumpyNumber(o)) { 527 o = to_python_int(o); 528 } 529 530 version(Python_3_0_Or_Later) { 531 }else{ 532 if(PyInt_Check(o)) { 533 C_long res = PyInt_AsLong(o); 534 handle_exception(); 535 static if(isUnsigned!T) { 536 if(res < 0) could_not_convert!T(o, format("%s out of bounds [%s, %s]", res, 0, T.max)); 537 if(T.max < res) could_not_convert!T(o,format("%s out of bounds [%s, %s]", res, 0, T.max)); 538 return cast(T) res; 539 }else static if(isSigned!T) { 540 if(T.min > res) could_not_convert!T(o, format("%s out of bounds [%s, %s]", res, T.min, T.max)); 541 if(T.max < res) could_not_convert!T(o, format("%s out of bounds [%s, %s]", res, T.min, T.max)); 542 return cast(T) res; 543 } 544 } 545 } 546 if(PyLong_Check(o)) { 547 static if(isUnsigned!T) { 548 static assert(T.sizeof <= C_ulonglong.sizeof); 549 C_ulonglong res = PyLong_AsUnsignedLongLong(o); 550 handle_exception(); 551 // no overflow from python to C_ulonglong, 552 // overflow from C_ulonglong to T? 553 if(T.max < res) could_not_convert!T(o); 554 return cast(T) res; 555 }else static if(isSigned!T) { 556 static assert(T.sizeof <= C_longlong.sizeof); 557 C_longlong res = PyLong_AsLongLong(o); 558 handle_exception(); 559 // no overflow from python to C_longlong, 560 // overflow from C_longlong to T? 561 if(T.min > res) could_not_convert!T(o); 562 if(T.max < res) could_not_convert!T(o); 563 return cast(T) res; 564 } 565 } 566 567 return python_to_d_try_extends!T(o); 568 } else static if (isBoolean!T) { 569 if (isPyNumber(o) || isNumpyNumber(o)) { 570 int res = PyObject_IsTrue(o); 571 return res == 1; 572 } 573 return python_to_d_try_extends!T(o); 574 } 575 576 assert(0); 577 } 578 579 PyObject* to_python_int(PyObject* o) { 580 auto builtins = new PydObject(PyEval_GetBuiltins()); 581 auto int_ = builtins["int"]; 582 return int_(o).to_d!(PyObject*)(); 583 } 584 585 T python_to_d_try_extends(T) (PyObject* o) { 586 if (from_converter_registry!(T).dg) { 587 return from_converter_registry!(T).dg(o); 588 } 589 could_not_convert!(T)(o); 590 assert(0); 591 } 592 593 T python_to_d_tuple(T) (PyObject* o) { 594 T.Types tuple; 595 auto len = PyTuple_Size(o); 596 if(len != T.Types.length) could_not_convert!T(o); 597 foreach(i,_t; T.Types) { 598 auto obj = Py_XINCREF(PyTuple_GetItem(o, i)); 599 tuple[i] = python_to_d!_t(obj); 600 Py_DECREF(obj); 601 } 602 return T(tuple); 603 } 604 605 T python_to_d_complex(T) (PyObject* o) { 606 import util.conv; 607 static if (is(Unqual!T _unused : Complex!F, F)) { 608 double real_ = python_to_d!double(PyObject_GetAttrString(o, "real")); 609 handle_exception(); 610 double imag = python_to_d!double(PyObject_GetAttrString(o, "imag")); 611 handle_exception(); 612 return complex!(F,F)(real_, imag); 613 }else static assert(false); 614 } 615 616 T python_to_d_bigint(T) (PyObject* o) { 617 string num_str = python_to_d!string(o); 618 if(num_str.endsWith("L")) num_str = num_str[0..$-1]; 619 return BigInt(num_str); 620 } 621 622 T python_to_d_string(T) (PyObject* o) { 623 alias Unqual!(typeof(T.init[0])) C; 624 PyObject* str; 625 if(PyBytes_Check(o)) { 626 static if(is(C == char)) { 627 str = o; 628 }else{ 629 version(Python_3_0_Or_Later) { 630 str = PyObject_Str(o); 631 if(!str) handle_exception(); 632 }else{ 633 str = PyObject_Unicode(o); 634 if(!str) handle_exception(); 635 } 636 } 637 }else if(PyUnicode_Check(o)) { 638 str = o; 639 }else { 640 str = PyObject_Repr(o); 641 if(!str) handle_exception(); 642 version(Python_3_0_Or_Later) { 643 }else{ 644 static if(!is(C == char)) { 645 str = PyObject_Unicode(str); 646 if(!str) handle_exception(); 647 } 648 } 649 } 650 static if(is(C == char)) { 651 if(PyBytes_Check(str)) { 652 const(char)* res = PyBytes_AsString(str); 653 if(!res) handle_exception(); 654 return to!T(res); 655 } 656 } 657 658 if(PyUnicode_Check(str)) { 659 static if(is(C == char)) { 660 PyObject* utf8 = PyUnicode_AsUTF8String(str); 661 if(!utf8) handle_exception(); 662 const(char)* res = PyBytes_AsString(utf8); 663 if(!res) handle_exception(); 664 return to!T(res); 665 }else static if(is(C == wchar)) { 666 PyObject* utf16 = PyUnicode_AsUTF16String(str); 667 if(!utf16) handle_exception(); 668 // PyUnicode_AsUTF16String puts a BOM character in front of 669 // string 670 auto ptr = cast(const(wchar)*)(PyBytes_AsString(utf16)+2); 671 Py_ssize_t len = PyBytes_Size(utf16)/2-1; 672 wchar[] ws = new wchar[](len); 673 ws[] = ptr[0 .. len]; 674 return cast(T) ws; 675 }else static if(is(C == dchar)) { 676 version(Python_2_6_Or_Later) { 677 PyObject* utf32 = PyUnicode_AsUTF32String(str); 678 if(!utf32) handle_exception(); 679 // PyUnicode_AsUTF32String puts a BOM character in front of 680 // string 681 auto ptr = cast(const(dchar)*)(PyBytes_AsString(utf32)+4); 682 Py_ssize_t len = PyBytes_Size(utf32)/4-1; 683 dchar[] ds = new dchar[](len); 684 ds[] = ptr[0 .. len]; 685 return cast(T) ds; 686 }else{ 687 return to!(T)(python_to_d!string(str)); 688 } 689 }else static assert(false, "what T is this!? " ~ T.stringof); 690 } 691 assert(0); 692 } 693 694 695 // (*^&* array doesn't implement the buffer interface, but we still 696 // want it to copy fast. 697 /// Convert an array.array object to a D object. 698 /// 699 /// Used by python_to_d. 700 T python_array_array_to_d(T)(PyObject* o) 701 if(isArray!T || IsStaticArrayPointer!T) { 702 static if(isPointer!T) 703 alias Unqual!(ElementType!(pointerTarget!T)) E; 704 else 705 alias Unqual!(ElementType!T) E; 706 if(o.ob_type !is array_array_Type) 707 could_not_convert!T(o, "not an array.array"); 708 arrayobject* arr_o = cast(arrayobject*) o; 709 // array.array's data can be got with a single memcopy. 710 enforce(arr_o.ob_descr, "array.ob_descr null!"); 711 char typecode = cast(char) arr_o.ob_descr.typecode; 712 if(!match_format_type!E(""~typecode)) { 713 could_not_convert!T(o, format("item mismatch: '%s' vs %s", 714 typecode, E.stringof)); 715 } 716 717 int itemsize = arr_o.ob_descr.itemsize; 718 if(itemsize != E.sizeof) 719 could_not_convert!T(o, 720 format("item size mismatch: %s vs %s", 721 itemsize, E.sizeof)); 722 Py_ssize_t count = Py_SIZE(arr_o); 723 if(count < 0) 724 could_not_convert!T(o, format("nonsensical array length: %s", 725 count)); 726 MatrixInfo!T.unqual _array; 727 static if(isDynamicArray!T) { 728 _array = new MatrixInfo!T.unqual(count); 729 }else { 730 if(!MatrixInfo!T.check([count])) 731 could_not_convert!T(o, 732 format("length mismatch: %s vs %s", count, T.length)); 733 } 734 // copy data, don't take slice 735 static if(isPointer!(typeof(_array))) { 736 memcpy((*_array).ptr, arr_o.ob_item, count*itemsize); 737 }else{ 738 memcpy(_array.ptr, arr_o.ob_item, count*itemsize); 739 } 740 //_array[] = cast(E[]) arr_o.ob_item[0 .. count*itemsize]; 741 return cast(T) _array; 742 } 743 744 /** 745 Convert a d array to a python array.array. 746 array.array does not support 8 byte integers. 747 748 Not used by d_to_python. 749 */ 750 PyObject* d_to_python_array_array(T)(T t) 751 if((isArray!T || IsStaticArrayPointer!T) && 752 MatrixInfo!T.ndim == 1 && 753 SimpleFormatType!(MatrixInfo!T.MatrixElementType).supported) { 754 755 alias MatrixInfo!T.MatrixElementType ME; 756 PyObject* pyformat = SimpleFormatType!ME.pyType(); 757 PyObject* args = PyTuple_New(1); 758 PyTuple_SetItem(args, 0, pyformat); 759 scope(exit) Py_DECREF(args); 760 PyObject* obj = array_array_Type.tp_new(array_array_Type, args, null); 761 if(!obj) handle_exception(); 762 arrayobject* arr_o = cast(arrayobject*) obj; 763 Py_ssize_t[] shape = MatrixInfo!T.build_shape(t); 764 size_t datalen = ME.sizeof*shape[0]; 765 Py_SET_SIZE(arr_o, shape[0]); 766 void* data = PyMem_Malloc(datalen); 767 static if(isPointer!T) { 768 memcpy(data, t, datalen); 769 }else { 770 memcpy(data, t.ptr, datalen); 771 } 772 arr_o.ob_item = cast(ubyte*) data; 773 return obj; 774 } 775 776 /** 777 Convert a D object to python bytes (str, in python 2). 778 */ 779 PyObject* d_to_python_bytes(T)(T t) if(is(T == string)) { 780 return PyBytes_FromStringAndSize(t.ptr, cast(Py_ssize_t) t.length); 781 } 782 783 /** Convert an iterable Python object to a D object. 784 * 785 * Used by python_to_d. 786 */ 787 T python_iter_to_d(T)(PyObject* o) if(isArray!T || IsStaticArrayPointer!T) { 788 static if(isPointer!T) 789 alias Unqual!(ElementType!(pointerTarget!T)) E; 790 else 791 alias Unqual!(ElementType!T) E; 792 PyObject* iter = PyObject_GetIter(o); 793 if (iter is null) { 794 PyErr_Clear(); 795 could_not_convert!(T)(o); 796 } 797 scope(exit) Py_DECREF(iter); 798 Py_ssize_t len = PyObject_Length(o); 799 if (len == -1) { 800 PyErr_Clear(); 801 could_not_convert!(T)(o); 802 } 803 804 MatrixInfo!T.unqual _array; 805 static if(isDynamicArray!T) { 806 _array = new MatrixInfo!T.unqual(len); 807 }else static if(isStaticArray!T){ 808 if(len != T.length) 809 could_not_convert!T(o, 810 format("length mismatch: %s vs %s", 811 len, T.length)); 812 }else static if(isPointer!T){ 813 ubyte[] bufi = new ubyte[](pointerTarget!T.sizeof); 814 _array = cast(MatrixInfo!T.unqual)(bufi.ptr); 815 } 816 int i = 0; 817 PyObject* item = PyIter_Next(iter); 818 while (item) { 819 try { 820 _array[i] = python_to_d!(E)(item); 821 } catch(PydConversionException e) { 822 Py_DECREF(item); 823 // We re-throw the original conversion exception, rather than 824 // complaining about being unable to convert to an array. The 825 // partially constructed array is left to the GC. 826 throw e; 827 } 828 ++i; 829 Py_DECREF(item); 830 item = PyIter_Next(iter); 831 } 832 return cast(T) _array; 833 } 834 835 bool isPyNumber(PyObject* obj) { 836 version(Python_3_0_Or_Later) { 837 return 838 PyLong_Check(obj) || 839 PyFloat_Check(obj); 840 }else{ 841 return 842 PyInt_Check(obj) || 843 PyLong_Check(obj) || 844 PyFloat_Check(obj); 845 } 846 } 847 848 const(char)[] type_name(PyObject* obj) { 849 auto type = cast(PyTypeObject*)PyObject_Type(obj); 850 return type.tp_name[0 .. strlen(type.tp_name)]; 851 } 852 853 bool isNumpyBool(PyObject* obj) { 854 switch(type_name(obj)) { 855 case "numpy.bool_": 856 return true; 857 default: 858 return false; 859 } 860 } 861 862 bool isNumpyInteger(PyObject* obj) { 863 switch(type_name(obj)) { 864 case "numpy.int8": 865 case "numpy.int16": 866 case "numpy.int32": 867 case "numpy.int64": 868 case "numpy.uint8": 869 case "numpy.uint16": 870 case "numpy.uint32": 871 case "numpy.uint64": 872 return true; 873 default: 874 return false; 875 } 876 } 877 878 bool isNumpyFloat(PyObject* obj) { 879 switch(type_name(obj)) { 880 case "numpy.float32": 881 case "numpy.float64": 882 return true; 883 default: 884 return false; 885 } 886 } 887 888 bool isNumpyComplexNumber(PyObject* obj) { 889 switch(type_name(obj)) { 890 case "numpy.complex32": 891 case "numpy.complex64": 892 return true; 893 default: 894 return false; 895 } 896 } 897 898 bool isNumpyNumber(PyObject* obj) { 899 return isNumpyBool(obj) || isNumpyInteger(obj) || isNumpyFloat(obj); 900 } 901 902 version(Python_2_6_Or_Later) { 903 /// Convert a Python new-style buffer to a D object. 904 /// 905 /// Used by python_to_d. 906 T python_buffer_to_d(T)(PyObject* o) 907 if (isArray!T || IsStaticArrayPointer!T) { 908 PydObject bob = new PydObject(borrowed(o)); 909 auto buf = bob.buffer_view(); 910 alias MatrixInfo!T.MatrixElementType ME; 911 MatrixInfo!T.unqual _array; 912 /+ 913 if(buf.itemsize != ME.sizeof) 914 could_not_convert!T(o, format("item size mismatch: %s vs %s", 915 buf.itemsize, ME.sizeof)); 916 +/ 917 if(!match_format_type!ME(buf.format)) { 918 could_not_convert!T(o, format("item type mismatch: '%s' vs %s", 919 buf.format, ME.stringof)); 920 } 921 if(buf.has_nd) { 922 if(!MatrixInfo!T.check(buf.shape)) 923 could_not_convert!T(o, 924 format("dimension mismatch: %s vs %s", 925 buf.shape, MatrixInfo!T.dimstring)); 926 if(buf.c_contiguous) { 927 // woohoo! single memcpy 928 static if(MatrixInfo!T.isRectArray && isStaticArray!T) { 929 memcpy(_array.ptr, buf.buf.ptr, buf.buf.length); 930 }else{ 931 alias MatrixInfo!T.RectArrayType RectArrayType; 932 static if(!isStaticArray!(RectArrayType)) { 933 ubyte[] dbuf = new ubyte[](buf.buf.length); 934 memcpy(dbuf.ptr, buf.buf.ptr, buf.buf.length); 935 } 936 size_t rectsize = ME.sizeof; 937 size_t MErectsize = 1; 938 foreach(i; MatrixInfo!T.rectArrayAt .. MatrixInfo!T.ndim) { 939 rectsize *= buf.shape[i]; 940 MErectsize *= buf.shape[i]; 941 } 942 static if(MatrixInfo!T.isRectArray) { 943 static if(isPointer!T) 944 _array = cast(typeof(_array)) dbuf.ptr; 945 else { 946 static assert(isDynamicArray!T); 947 _array = cast(typeof(_array)) dbuf; 948 } 949 }else{ 950 // rubbish. much pointer pointing 951 size_t offset = 0; 952 static if(isDynamicArray!T) { 953 _array = new MatrixInfo!T.unqual(buf.shape[0]); 954 } 955 enum string xx = (MatrixInfo!T.matrixIter( 956 "_array", "buf.shape", "_indeces", 957 MatrixInfo!T.rectArrayAt, q{ 958 static if(isDynamicArray!(typeof($array_ixn))) { 959 $array_ixn = new typeof($array_ixn)(buf.shape[$i+1]); 960 } 961 static if(is(typeof($array_ixn) == RectArrayType)) { 962 // should be innermost loop 963 assert(offset + rectsize <= buf.buf.length, 964 "uh oh: overflow!"); 965 alias typeof($array_ixn) rectarr; 966 static if(isStaticArray!rectarr) { 967 memcpy($array_ixn.ptr, buf.buf.ptr + offset, rectsize); 968 }else{ 969 static assert(isDynamicArray!rectarr); 970 971 $array_ixn = (cast(typeof($array_ixn.ptr))(dbuf.ptr + offset)) 972 [0 .. MErectsize]; 973 } 974 offset += rectsize; 975 } 976 }, 977 "")); 978 mixin(xx); 979 } 980 } 981 }else if(buf.fortran_contiguous) { 982 // really rubbish. no memcpy. 983 static if(isDynamicArray!T) { 984 _array = new MatrixInfo!T.unqual(buf.shape[0]); 985 }else static if(isPointer!T) { 986 ubyte[] dubuf = new ubyte[](buf.buffer.len); 987 _array = cast(typeof(_array)) dubuf.ptr; 988 989 } 990 enum string xx = (MatrixInfo!T.matrixIter( 991 "_array", "buf.shape", "_indeces", 992 MatrixInfo!T.ndim, q{ 993 static if(isDynamicArray!(typeof($array_ixn))) { 994 $array_ixn = new typeof($array_ixn)(buf.shape[$i+1]); 995 }else static if(is(typeof($array_ixn) == ME)) { 996 $array_ixn = buf.item!ME(cast(Py_ssize_t[]) _indeces); 997 } 998 }, 999 "")); 1000 mixin(xx); 1001 }else { 1002 // wut? 1003 could_not_convert!T(o,("todo: know what todo")); 1004 assert(0); 1005 } 1006 return cast(T) _array; 1007 }else if(buf.has_simple) { 1008 /* 1009 static if(isDynamicArray!T) { 1010 E[] array = new E[](buf.buf.length); 1011 }else static if(isStaticArray!T) { 1012 if(buf.buf.length != T.length) 1013 could_not_convert!T(o, 1014 format("length mismatch: %s vs %s", 1015 buf.buf.length, T.length)); 1016 E[T.length] array; 1017 } 1018 return cast(T) array; 1019 */ 1020 assert(0, "py jingo wat we do here?"); 1021 } 1022 return cast(T) _array; 1023 } 1024 } 1025 1026 /** 1027 Wrap a D input range as a python iterator object. 1028 1029 Does not work for UFCS ranges (e.g. arrays), classes 1030 */ 1031 auto wrap_range(Range)(Range range) if(is(Range == struct)) { 1032 static assert(!is(Range == RangeWrapper)); 1033 import core.memory; 1034 RangeWrapper wrap; 1035 // the hackery! the hackery! 1036 Range* keeper = cast(Range*) GC.calloc(Range.sizeof); 1037 std.algorithm.move(range, *keeper); 1038 wrap.range = cast(void*) keeper; 1039 wrap.tid = typeid(Range); 1040 wrap.empty = dg_wrapper(keeper, &Range.empty); 1041 wrap.popFront = dg_wrapper(keeper, &Range.popFront); 1042 auto front_dg = 1043 dg_wrapper(keeper, cast(ElementType!Range function()) &Range.front); 1044 wrap.front = delegate PyObject*() { 1045 return d_to_python(front_dg()); 1046 }; 1047 return wrap; 1048 } 1049 1050 /** 1051 Wrapper type wrapping a D input range as a python iterator object 1052 1053 Lives in reserved python module "pyd". 1054 */ 1055 struct RangeWrapper { 1056 void* range; 1057 void delegate() popFront; 1058 PyObject* delegate() front; 1059 bool delegate() empty; 1060 TypeInfo tid; 1061 1062 RangeWrapper* iter() { 1063 return &this; 1064 } 1065 PyObject* next() { 1066 if(this.empty()) { 1067 return null; 1068 }else { 1069 auto result = d_to_python(this.front()); 1070 this.popFront(); 1071 return result; 1072 } 1073 } 1074 } 1075 1076 /// Check T against format 1077 /// See_Also: 1078 /// <a href='http://docs.python.org/library/struct.html#struct-format-strings'> 1079 /// Struct Format Strings </a> 1080 bool match_format_type(T)(string format) { 1081 alias T S; 1082 size_t S_size = S.sizeof; 1083 enforce(format.length > 0); 1084 1085 bool native_size = false; 1086 switch(format[0]) { 1087 case '@': 1088 // this (*&^& function is not defined 1089 //PyBuffer_SizeFromFormat() 1090 native_size = true; 1091 goto case; 1092 case '=','<','>','!': 1093 format = format[1 .. $]; 1094 default: 1095 break; 1096 } 1097 // by typeishness 1098 switch(format[0]) { 1099 case 'x', 's', 'p': 1100 // don't support these 1101 enforce(false, "unsupported format: " ~ format); 1102 case 'c': 1103 break; 1104 case 'b', 'h','i','l','q': 1105 if(!isSigned!S) return false; 1106 else break; 1107 case 'B', 'H', 'I', 'L','Q': 1108 if(!isUnsigned!S) return false; 1109 else break; 1110 case 'f','d': 1111 if(!isFloatingPoint!S) return false; 1112 else break; 1113 case '?': 1114 if(!isBoolean!S) return false; 1115 case 'Z': 1116 if (format.length > 1) { 1117 static if(is(S : Complex!F, F)) { 1118 S_size = F.sizeof; 1119 }else{ 1120 return false; 1121 } 1122 } 1123 format = format[1..$]; 1124 break; 1125 default: 1126 enforce(false, "unknown format: " ~ format); 1127 } 1128 1129 // by sizeishness 1130 if(native_size) { 1131 // grr 1132 assert(0, "todo"); 1133 }else{ 1134 switch(format[0]) { 1135 case 'c','b','B','?': 1136 return (S_size == 1); 1137 case 'h','H': 1138 return (S_size == 2); 1139 case 'i','I','l','L','f': 1140 return (S_size == 4); 1141 case 'q','Q','d': 1142 return (S_size == 8); 1143 default: 1144 enforce(false, "unknown format: " ~ format); 1145 assert(0); // seriously, d? 1146 1147 } 1148 } 1149 } 1150 1151 /// generate a struct format string from T 1152 template SimpleFormatType(T) { 1153 enum supported = 1154 (isFloatingPoint!T && (T.sizeof == 4 || T.sizeof == 8) || 1155 isIntegral!T); 1156 1157 PyObject* pyType() { 1158 //assert(supported); 1159 static if(supported) { 1160 version(Python_3_0_Or_Later) { 1161 alias to_python = d_to_python; 1162 }else{ 1163 // stinking py2 array won't take unicode 1164 alias to_python = d_to_python_bytes; 1165 } 1166 static if(isFloatingPoint!T && T.sizeof == 4) { 1167 return to_python("f"); 1168 }else static if(isFloatingPoint!T && T.sizeof == 8) { 1169 return to_python("d"); 1170 }else static if(isIntegral!T && T.sizeof == 1) { 1171 return to_python(isSigned!T ? "b" : "B"); 1172 }else static if(isIntegral!T && T.sizeof == 2) { 1173 return to_python(isSigned!T ? "h" : "H"); 1174 }else static if(isIntegral!T && T.sizeof == 4) { 1175 return to_python(isSigned!T ? "i" : "I"); 1176 }else static if(isIntegral!T && T.sizeof == 8) { 1177 return to_python(isSigned!T ? "q" : "Q"); 1178 } 1179 return null; 1180 }else{ 1181 assert(false); 1182 } 1183 } 1184 } 1185 1186 1187 /** 1188 Check that T is a pointer to a rectangular static array. 1189 */ 1190 template IsStaticArrayPointer(T) { 1191 template _Inner(S) { 1192 static if(isStaticArray!S) { 1193 enum _Inner = _Inner!(ElementType!S); 1194 } else static if(isArray!S || isPointer!S) { 1195 enum _Inner = false; 1196 }else { 1197 enum _Inner = true; 1198 } 1199 } 1200 static if(isPointer!T) { 1201 enum bool IsStaticArrayPointer = _Inner!(pointerTarget!T); 1202 }else{ 1203 enum bool IsStaticArrayPointer = false; 1204 } 1205 } 1206 1207 /** 1208 Some reflective information about multidimensional arrays 1209 1210 Handles dynamic arrays, static arrays, and pointers to static arrays. 1211 */ 1212 template MatrixInfo(T) if(isArray!T || IsStaticArrayPointer!T) { 1213 template ElementType2(_T) { 1214 static if(isSomeString!_T) { 1215 alias ElementType2=_T; 1216 }else{ 1217 alias ElementType2=ElementType!_T; 1218 } 1219 } 1220 1221 template _dim_list(T, dimi...) { 1222 static if(isSomeString!T) { 1223 alias dimi list; 1224 alias T elt; 1225 alias Unqual!T unqual; 1226 } else static if(isDynamicArray!T) { 1227 alias _dim_list!(ElementType2!T, dimi,-1) next; 1228 alias next.list list; 1229 alias next.elt elt; 1230 alias next.unqual[] unqual; 1231 }else static if(isStaticArray!T) { 1232 alias _dim_list!(ElementType2!T, dimi, cast(Py_ssize_t) T.length) next; 1233 alias next.list list; 1234 alias next.elt elt; 1235 alias next.unqual[T.length] unqual; 1236 }else { 1237 alias dimi list; 1238 alias T elt; 1239 alias Unqual!T unqual; 1240 } 1241 } 1242 1243 string tuple2string(T...)() { 1244 string s = "["; 1245 foreach(i, t; T) { 1246 if(t == -1) s ~= "*"; 1247 else s ~= to!string(t); 1248 if(i == T.length-1) { 1249 s ~= "]"; 1250 }else{ 1251 s ~= ","; 1252 } 1253 } 1254 return s; 1255 } 1256 1257 /** 1258 Build shape from t. Assumes all arrays in a dimension are initialized 1259 and of uniform length. 1260 */ 1261 Py_ssize_t[] build_shape(T t) { 1262 Py_ssize_t[] shape = new Py_ssize_t[](ndim); 1263 mixin(shape_builder_mixin("t", "shape")); 1264 return shape; 1265 } 1266 1267 string shape_builder_mixin(string arr_name, string shape_name) { 1268 static if(isPointer!T) { 1269 string s_ixn = "(*" ~ arr_name ~ ")"; 1270 }else{ 1271 string s_ixn = arr_name; 1272 } 1273 string s = ""; 1274 foreach(i; 0 .. ndim) { 1275 s ~= shape_name ~ "["~ to!string(i) ~"] = cast(Py_ssize_t)" ~ s_ixn ~ ".length;"; 1276 s_ixn ~= "[0]"; 1277 } 1278 return s; 1279 } 1280 1281 /** 1282 Ensures that T can store a matrix of _shape shape. 1283 */ 1284 bool check(Py_ssize_t[] shape) { 1285 if (shape.length != dim_list.length) return false; 1286 foreach(i, d; dim_list) { 1287 static if(dim_list[i] == -1) continue; 1288 else if(d != shape[i]) return false; 1289 } 1290 return true; 1291 } 1292 1293 /** 1294 Generate a mixin string of nested for loops that iterate over the 1295 first ndim dimensions of an array of type T (or, preferrably 1296 MatrixInfo!T.unqual). 1297 1298 Params: 1299 arr_name = name of array to iterate. 1300 shape_name = name of array of dimension lengths. 1301 index_name = name to use for index vector. Declared in a new nested scoped. 1302 ndim = number of dimensions to iterate over. 1303 pre_code = code to mixin each for loop before beginning the nested for loop. 1304 post_code = code to mix in to each for loop after finishing the nested for loop. 1305 */ 1306 1307 string matrixIter(string arr_name, string shape_name, 1308 string index_name, 1309 size_t ndim, 1310 string pre_code, string post_code) { 1311 string s_begin = "{\n"; 1312 string s_end = "}\n"; 1313 static if(isPointer!T) { 1314 string s_ixn = "(*" ~ arr_name ~ ")"; 1315 }else{ 1316 string s_ixn = arr_name; 1317 } 1318 1319 s_begin ~= "size_t[" ~ to!string(ndim) ~ "] " ~ index_name ~ ";\n"; 1320 foreach(i; 0 .. ndim) { 1321 string s_i = to!string(i); 1322 s_ixn ~= "["~ index_name ~ "[" ~ s_i ~ "]]"; 1323 string index = index_name~ "[" ~ s_i ~ "]"; 1324 string shape_i = shape_name ~ "[" ~ s_i ~ "]"; 1325 s_begin ~= "for("~index~" = 0;" ~index ~ " < " ~ shape_i ~ 1326 "; " ~ index ~ "++) {"; 1327 s_end ~= "}\n"; 1328 1329 string pre_code_i = replace(pre_code, "$array_ixn", s_ixn); 1330 pre_code_i = replace(pre_code_i, "$i", s_i); 1331 s_begin ~= pre_code_i; 1332 string post_code_i = replace(post_code, "$array_ixn", s_ixn); 1333 post_code_i = replace(post_code_i, "$i", s_i); 1334 s_end ~= post_code_i; 1335 } 1336 return s_begin ~ s_end; 1337 } 1338 1339 static if(isPointer!T && isStaticArray!(pointerTarget!T)) { 1340 alias _dim_list!(pointerTarget!T) _dim; 1341 /// T, with all nonmutable qualifiers stripped away. 1342 alias _dim.unqual* unqual; 1343 }else{ 1344 alias _dim_list!T _dim; 1345 alias _dim.unqual unqual; 1346 } 1347 /// tuple of dimensions of T. 1348 /// dim_list[0] will be the dimension furthest from the MatrixElementType 1349 /// i.e. for double[1][2][3], dim_list == (3, 2, 1). 1350 /// Lists -1 as dimension of dynamic arrays. 1351 alias _dim.list dim_list; 1352 /// number of dimensions of this matrix 1353 enum ndim = dim_list.length; 1354 /// T is a RectArray if: 1355 /// * it is any multidimensional static array (or a pointer to) 1356 /// * it is a 1 dimensional dynamic array 1357 enum bool isRectArray = staticIndexOf!(-1, dim_list) == -1 || dim_list.length == 1; 1358 //(1,2,3) -> rectArrayAt == 0 1359 //(-1,2,3) -> rectArrayAt == 1 == 3 - 2 == len - max(indexof_rev, 1) 1360 //(-1,-1,1) -> rectArrayAt == 2 == 3 - 1 == len - max(indexof_rev,1) 1361 //(-1,-1,-1) -> rectArrayAt == 2 == 3 - 1 == len - max(indexof_rev,1) 1362 //(2,2,-1) -> rectArrayAt == 2 1363 enum size_t indexof_rev = staticIndexOf!(-1, Reverse!dim_list); 1364 /// Highest dimension where it and all subsequent dimensions form a 1365 /// RectArray. 1366 enum size_t rectArrayAt = isRectArray ? 0 : dim_list.length - max(indexof_rev, 1); 1367 template _rect_type(S, size_t i) { 1368 static if(i == rectArrayAt) { 1369 alias S _rect_type; 1370 } else { 1371 alias _rect_type!(ElementType!S, i+1) _rect_type; 1372 } 1373 } 1374 /// unqualified highest dimension subtype of T forming RectArray 1375 alias _rect_type!(unqual, 0) RectArrayType; 1376 /// Pretty string of dimension list for T 1377 enum string dimstring = tuple2string!(dim_list)(); 1378 /// Matrix element type of T 1379 /// E.g. immutable(double) for T=immutable(double[4][4]) 1380 alias _dim.elt MatrixElementType; 1381 } 1382 1383 @property PyTypeObject* array_array_Type() { 1384 static PyTypeObject* m_type; 1385 if(!m_type) { 1386 PyObject* array = PyImport_ImportModule("array"); 1387 scope(exit) Py_XDECREF(array); 1388 m_type = cast(PyTypeObject*) PyObject_GetAttrString(array, "array"); 1389 } 1390 return m_type; 1391 } 1392 1393 alias python_to_d!(Object) python_to_d_Object; 1394 1395 void could_not_convert(T) (PyObject* o, string reason = "", 1396 string file = __FILE__, size_t line = __LINE__) { 1397 // Pull out the name of the type of this Python object, and the 1398 // name of the D type. 1399 string py_typename, d_typename; 1400 PyObject* py_type, py_type_str; 1401 py_type = PyObject_Type(o); 1402 if (py_type is null) { 1403 py_typename = "<unknown>"; 1404 } else { 1405 py_type_str = PyObject_GetAttrString(py_type, cast(const(char)*) "__name__".ptr); 1406 Py_DECREF(py_type); 1407 if (py_type_str is null) { 1408 py_typename = "<unknown>"; 1409 } else { 1410 py_typename = python_to_d!string(py_type_str); 1411 Py_DECREF(py_type_str); 1412 } 1413 } 1414 d_typename = typeid(T).toString(); 1415 string because; 1416 if(reason != "") because = format(" because: %s", reason); 1417 throw new PydConversionException( 1418 format("Couldn't convert Python type '%s' to D type '%s'%s", 1419 py_typename, 1420 d_typename, 1421 because), 1422 file, line 1423 ); 1424 } 1425 1426 // stuff this down here until we can figure out what to do with it. 1427 // Python-header-file: Modules/arraymodule.c: 1428 1429 struct arraydescr{ 1430 int typecode; 1431 int itemsize; 1432 PyObject* function(arrayobject*, Py_ssize_t) getitem; 1433 int function(arrayobject*, Py_ssize_t, PyObject*) setitem; 1434 } 1435 1436 struct arrayobject { 1437 mixin PyObject_VAR_HEAD; 1438 ubyte* ob_item; 1439 Py_ssize_t allocated; 1440 arraydescr* ob_descr; 1441 PyObject* weakreflist; /* List of weak references */ 1442 }