| | 415 | //----------------------------------------------------------------------------- |
|---|
| | 416 | // And now the reverse operation: wrapping a Python callable with a delegate. |
|---|
| | 417 | // These rely on a whole collection of nasty templates, but the result is both |
|---|
| | 418 | // flexible and pretty fast. |
|---|
| | 419 | // (Sadly, wrapping a Python callable with a regular function is not quite |
|---|
| | 420 | // possible.) |
|---|
| | 421 | //----------------------------------------------------------------------------- |
|---|
| | 422 | // The steps involved when calling this function are as follows: |
|---|
| | 423 | // 1) An instance of DPyWrappedFunc is made, and the callable placed within. |
|---|
| | 424 | // 2) The delegate type Dg is broken into its constituent parts. |
|---|
| | 425 | // 3) These parts are used to get the proper overload of DPyWrappedFunc.fn |
|---|
| | 426 | // 4) A delegate to DPyWrappedFunc.fn is returned. |
|---|
| | 427 | // 5) When fn is called, it attempts to cram the arguments into the callable. |
|---|
| | 428 | // If Python objects to this, an exception is raised. Note that this means |
|---|
| | 429 | // any error in converting the callable to a given delegate can only be |
|---|
| | 430 | // detected at runtime. |
|---|
| | 431 | |
|---|
| | 432 | Dg DPyCallable_AsDelegate(Dg) (PyObject* c) { |
|---|
| | 433 | auto f = new DPyWrappedFunc(c); |
|---|
| | 434 | |
|---|
| | 435 | const uint ARGS = NumberOfArgs!(Dg); |
|---|
| | 436 | alias ReturnType!(Dg) Tr; |
|---|
| | 437 | static if (ARGS == 0) |
|---|
| | 438 | return &f.fn!(Tr); |
|---|
| | 439 | else static if (ARGS == 1) |
|---|
| | 440 | return &f.fn!(Tr, ArgType!(Dg, 1)); |
|---|
| | 441 | else static if (ARGS == 2) |
|---|
| | 442 | return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2)); |
|---|
| | 443 | else static if (ARGS == 3) |
|---|
| | 444 | return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3)); |
|---|
| | 445 | else static if (ARGS == 4) |
|---|
| | 446 | return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3), ArgType!(Dg, 4)); |
|---|
| | 447 | else static if (ARGS == 5) |
|---|
| | 448 | return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3), ArgType!(Dg, 4), ArgType!(Dg, 5)); |
|---|
| | 449 | else static if (ARGS == 6) |
|---|
| | 450 | return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3), ArgType!(Dg, 4), ArgType!(Dg, 5), ArgType!(Dg, 6)); |
|---|
| | 451 | else static if (ARGS == 7) |
|---|
| | 452 | return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3), ArgType!(Dg, 4), ArgType!(Dg, 5), ArgType!(Dg, 6), ArgType!(Dg, 7)); |
|---|
| | 453 | else static if (ARGS == 8) |
|---|
| | 454 | return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3), ArgType!(Dg, 4), ArgType!(Dg, 5), ArgType!(Dg, 6), ArgType!(Dg, 7), ArgType!(Dg, 8)); |
|---|
| | 455 | else static if (ARGS == 9) |
|---|
| | 456 | return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3), ArgType!(Dg, 4), ArgType!(Dg, 5), ArgType!(Dg, 6), ArgType!(Dg, 7), ArgType!(Dg, 8), ArgType!(Dg, 9)); |
|---|
| | 457 | else static if (ARGS == 10) |
|---|
| | 458 | return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3), ArgType!(Dg, 4), ArgType!(Dg, 5), ArgType!(Dg, 6), ArgType!(Dg, 7), ArgType!(Dg, 8), ArgType!(Dg, 9), ArgType!(Dg, 10)); |
|---|
| | 459 | else static assert(false, "Unsupported number of args in delegate type."); |
|---|
| | 460 | } |
|---|
| | 461 | |
|---|
| | 462 | class Dummy { } |
|---|
| | 463 | |
|---|
| | 464 | private |
|---|
| | 465 | class DPyWrappedFunc { |
|---|
| | 466 | PyObject* callable; |
|---|
| | 467 | |
|---|
| | 468 | this(PyObject* c) { callable = c; Py_INCREF(c); } |
|---|
| | 469 | ~this() { Py_DECREF(callable); } |
|---|
| | 470 | |
|---|
| | 471 | Tr boilerplate(Tr)(PyObject* ret) { |
|---|
| | 472 | if (ret is null) handle_exception(); |
|---|
| | 473 | scope(exit) Py_DECREF(ret); |
|---|
| | 474 | return d_type!(Tr)(ret); |
|---|
| | 475 | } |
|---|
| | 476 | |
|---|
| | 477 | Tr fn(Tr)() { |
|---|
| | 478 | return boilerplate!(Tr)(call()); |
|---|
| | 479 | } |
|---|
| | 480 | |
|---|
| | 481 | Tr fn(Tr, T1)(T1 t1) { |
|---|
| | 482 | return boilerplate!(Tr)(call(t1)); |
|---|
| | 483 | } |
|---|
| | 484 | |
|---|
| | 485 | Tr fn(Tr, T1, T2)(T1 t1, T2 t2) { |
|---|
| | 486 | return boilerplate!(Tr)(call(t1, t2)); |
|---|
| | 487 | } |
|---|
| | 488 | |
|---|
| | 489 | Tr fn(Tr, T1, T2, T3)(T1 t1, T2 t2, T3 t3) { |
|---|
| | 490 | return boilerplate!(Tr)(call(t1, t2, t3)); |
|---|
| | 491 | } |
|---|
| | 492 | |
|---|
| | 493 | Tr fn(Tr, T1, T2, T3, T4)(T1 t1, T2 t2, T3 t3, T4 t4) { |
|---|
| | 494 | return boilerplate!(Tr)(call(t1, t2, t3, t4)); |
|---|
| | 495 | } |
|---|
| | 496 | |
|---|
| | 497 | Tr fn(Tr, T1, T2, T3, T4, T5)(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) { |
|---|
| | 498 | return boilerplate!(Tr)(call(t1, t2, t3, t4, t5)); |
|---|
| | 499 | } |
|---|
| | 500 | |
|---|
| | 501 | Tr fn(Tr, T1, T2, T3, T4, T5, T6)(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) { |
|---|
| | 502 | return boilerplate!(Tr)(call(t1, t2, t3, t4, t5, t6)); |
|---|
| | 503 | } |
|---|
| | 504 | |
|---|
| | 505 | Tr fn(Tr, T1, T2, T3, T4, T5, T6, T7)(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) { |
|---|
| | 506 | return boilerplate!(Tr)(call(t1, t2, t3, t4, t5, t6, t7)); |
|---|
| | 507 | } |
|---|
| | 508 | |
|---|
| | 509 | Tr fn(Tr, T1, T2, T3, T4, T5, T6, T7, T8)(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) { |
|---|
| | 510 | return boilerplate!(Tr)(call(t1, t2, t3, t4, t5, t6, t7, t8)); |
|---|
| | 511 | } |
|---|
| | 512 | |
|---|
| | 513 | Tr fn(Tr, T1, T2, T3, T4, T5, T6, T7, T8, T9)(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) { |
|---|
| | 514 | return boilerplate!(Tr)(call(t1, t2, t3, t4, t5, t6, t7, t8, t9)); |
|---|
| | 515 | } |
|---|
| | 516 | |
|---|
| | 517 | Tr fn(Tr, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10) { |
|---|
| | 518 | return boilerplate!(Tr)(call(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)); |
|---|
| | 519 | } |
|---|
| | 520 | |
|---|
| | 521 | template call(T1=Dummy, T2=Dummy, T3=Dummy, T4=Dummy, T5=Dummy, T6=Dummy, T7=Dummy, T8=Dummy, T9=Dummy, T10=Dummy) { |
|---|
| | 522 | PyObject* call (T1 t1=null, T2 t2=null, T3 t3=null, T4 t4=null, T5 t5=null, T6 t6=null, T7 t7=null, T8 t8=null, T9 t9=null, T10 t10=null) { |
|---|
| | 523 | static if (!is(T10 == Dummy)) |
|---|
| | 524 | const uint ARGS = 10; |
|---|
| | 525 | else static if (!is(T9 == Dummy)) |
|---|
| | 526 | const uint ARGS = 9; |
|---|
| | 527 | else static if (!is(T8 == Dummy)) |
|---|
| | 528 | const uint ARGS = 8; |
|---|
| | 529 | else static if (!is(T7 == Dummy)) |
|---|
| | 530 | const uint ARGS = 7; |
|---|
| | 531 | else static if (!is(T6 == Dummy)) |
|---|
| | 532 | const uint ARGS = 6; |
|---|
| | 533 | else static if (!is(T5 == Dummy)) |
|---|
| | 534 | const uint ARGS = 5; |
|---|
| | 535 | else static if (!is(T4 == Dummy)) |
|---|
| | 536 | const uint ARGS = 4; |
|---|
| | 537 | else static if (!is(T3 == Dummy)) |
|---|
| | 538 | const uint ARGS = 3; |
|---|
| | 539 | else static if (!is(T2 == Dummy)) |
|---|
| | 540 | const uint ARGS = 2; |
|---|
| | 541 | else static if (!is(T1 == Dummy)) |
|---|
| | 542 | const uint ARGS = 1; |
|---|
| | 543 | else |
|---|
| | 544 | const uint ARGS = 0; |
|---|
| | 545 | PyObject* t = PyTuple_New(ARGS); |
|---|
| | 546 | if (t is null) return null; |
|---|
| | 547 | scope(exit) Py_DECREF(t); |
|---|
| | 548 | static if (!is(T10 == Dummy)) |
|---|
| | 549 | PyTuple_SetItem(t, 9, _py(t10)); |
|---|
| | 550 | static if (!is(T9 == Dummy)) |
|---|
| | 551 | PyTuple_SetItem(t, 8, _py(t9)); |
|---|
| | 552 | static if (!is(T8 == Dummy)) |
|---|
| | 553 | PyTuple_SetItem(t, 7, _py(t8)); |
|---|
| | 554 | static if (!is(T7 == Dummy)) |
|---|
| | 555 | PyTuple_SetItem(t, 6, _py(t7)); |
|---|
| | 556 | static if (!is(T6 == Dummy)) |
|---|
| | 557 | PyTuple_SetItem(t, 5, _py(t6)); |
|---|
| | 558 | static if (!is(T5 == Dummy)) |
|---|
| | 559 | PyTuple_SetItem(t, 4, _py(t5)); |
|---|
| | 560 | static if (!is(T4 == Dummy)) |
|---|
| | 561 | PyTuple_SetItem(t, 3, _py(t4)); |
|---|
| | 562 | static if (!is(T3 == Dummy)) |
|---|
| | 563 | PyTuple_SetItem(t, 2, _py(t3)); |
|---|
| | 564 | static if (!is(T2 == Dummy)) |
|---|
| | 565 | PyTuple_SetItem(t, 1, _py(t2)); |
|---|
| | 566 | static if (!is(T1 == Dummy)) |
|---|
| | 567 | PyTuple_SetItem(t, 0, _py(t1)); |
|---|
| | 568 | return PyObject_CallObject(callable, t); |
|---|
| | 569 | } |
|---|
| | 570 | } |
|---|
| | 571 | } |
|---|