From da1c5f1cb359289d081bae34eca9bf2162f06ad2 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 29 Jan 2021 13:42:52 -0800 Subject: [PATCH 1/3] Copying files as-is from branch test_unique_ptr_member (PR #2672). --- tests/test_type_caster_bare_interface.cpp | 211 ++++++++++++++++++++++ tests/test_type_caster_bare_interface.py | 41 +++++ 2 files changed, 252 insertions(+) create mode 100644 tests/test_type_caster_bare_interface.cpp create mode 100644 tests/test_type_caster_bare_interface.py diff --git a/tests/test_type_caster_bare_interface.cpp b/tests/test_type_caster_bare_interface.cpp new file mode 100644 index 0000000000..02b6281c2e --- /dev/null +++ b/tests/test_type_caster_bare_interface.cpp @@ -0,0 +1,211 @@ +#include "pybind11_tests.h" + +#include + +namespace pybind11_tests { +namespace type_caster_bare_interface { + +struct mpty {}; + +// clang-format off + +mpty rtrn_mpty_valu() { mpty obj; return obj; } +mpty&& rtrn_mpty_rref() { static mpty obj; return std::move(obj); } +mpty const& rtrn_mpty_cref() { static mpty obj; return obj; } +mpty& rtrn_mpty_mref() { static mpty obj; return obj; } +mpty const* rtrn_mpty_cptr() { return new mpty; } +mpty* rtrn_mpty_mptr() { return new mpty; } + +const char* pass_mpty_valu(mpty) { return "load_valu"; } +const char* pass_mpty_rref(mpty&&) { return "load_rref"; } +const char* pass_mpty_cref(mpty const&) { return "load_cref"; } +const char* pass_mpty_mref(mpty&) { return "load_mref"; } +const char* pass_mpty_cptr(mpty const*) { return "load_cptr"; } +const char* pass_mpty_mptr(mpty*) { return "load_mptr"; } + +std::shared_ptr rtrn_mpty_shmp() { return std::shared_ptr(new mpty); } +std::shared_ptr rtrn_mpty_shcp() { return std::shared_ptr(new mpty); } + +const char* pass_mpty_shmp(std::shared_ptr) { return "load_shmp"; } +const char* pass_mpty_shcp(std::shared_ptr) { return "load_shcp"; } + +std::unique_ptr rtrn_mpty_uqmp() { return std::unique_ptr(new mpty); } +std::unique_ptr rtrn_mpty_uqcp() { return std::unique_ptr(new mpty); } + +const char* pass_mpty_uqmp(std::unique_ptr) { return "load_uqmp"; } +const char* pass_mpty_uqcp(std::unique_ptr) { return "load_uqcp"; } + +// clang-format on + +} // namespace type_caster_bare_interface +} // namespace pybind11_tests + +namespace pybind11 { +namespace detail { + +using namespace pybind11_tests::type_caster_bare_interface; + +template <> +struct type_caster { + static constexpr auto name = _(); + + // static handle cast(mpty, ...) + // is redundant (leads to ambiguous overloads). + + static handle cast(mpty && /*src*/, return_value_policy /*policy*/, handle /*parent*/) { + return str("cast_rref").release(); + } + + static handle cast(mpty const & /*src*/, return_value_policy /*policy*/, handle /*parent*/) { + return str("cast_cref").release(); + } + + static handle cast(mpty & /*src*/, return_value_policy /*policy*/, handle /*parent*/) { + return str("cast_mref").release(); + } + + static handle cast(mpty const *src, return_value_policy /*policy*/, handle /*parent*/) { + delete src; + return str("cast_cptr").release(); + } + + static handle cast(mpty *src, return_value_policy /*policy*/, handle /*parent*/) { + delete src; + return str("cast_mptr").release(); + } + + template + using cast_op_type = conditional_t< + std::is_same, mpty const *>::value, + mpty const *, + conditional_t< + std::is_same, mpty *>::value, + mpty *, + conditional_t< + std::is_same::value, + mpty const &, + conditional_t::value, + mpty &, + conditional_t::value, mpty &&, mpty>>>>>; + + // clang-format off + + operator mpty() { return rtrn_mpty_valu(); } + operator mpty&&() && { return rtrn_mpty_rref(); } + operator mpty const&() { return rtrn_mpty_cref(); } + operator mpty&() { return rtrn_mpty_mref(); } + operator mpty const*() { static mpty obj; return &obj; } + operator mpty*() { static mpty obj; return &obj; } + + // clang-format on + + bool load(handle /*src*/, bool /*convert*/) { return true; } +}; + +template <> +struct type_caster> { + static constexpr auto name = _>(); + + static handle cast(const std::shared_ptr & /*src*/, + return_value_policy /*policy*/, + handle /*parent*/) { + return str("cast_shmp").release(); + } + + template + using cast_op_type = std::shared_ptr; + + operator std::shared_ptr() { return rtrn_mpty_shmp(); } + + bool load(handle /*src*/, bool /*convert*/) { return true; } +}; + +template <> +struct type_caster> { + static constexpr auto name = _>(); + + static handle cast(const std::shared_ptr & /*src*/, + return_value_policy /*policy*/, + handle /*parent*/) { + return str("cast_shcp").release(); + } + + template + using cast_op_type = std::shared_ptr; + + operator std::shared_ptr() { return rtrn_mpty_shcp(); } + + bool load(handle /*src*/, bool /*convert*/) { return true; } +}; + +template <> +struct type_caster> { + static constexpr auto name = _>(); + + static handle + cast(std::unique_ptr && /*src*/, return_value_policy /*policy*/, handle /*parent*/) { + return str("cast_uqmp").release(); + } + + template + using cast_op_type = std::unique_ptr; + + operator std::unique_ptr() { return rtrn_mpty_uqmp(); } + + bool load(handle /*src*/, bool /*convert*/) { return true; } +}; + +template <> +struct type_caster> { + static constexpr auto name = _>(); + + static handle cast(std::unique_ptr && /*src*/, + return_value_policy /*policy*/, + handle /*parent*/) { + return str("cast_uqcp").release(); + } + + template + using cast_op_type = std::unique_ptr; + + operator std::unique_ptr() { return rtrn_mpty_uqcp(); } + + bool load(handle /*src*/, bool /*convert*/) { return true; } +}; + +} // namespace detail +} // namespace pybind11 + +namespace pybind11_tests { +namespace type_caster_bare_interface { + +TEST_SUBMODULE(type_caster_bare_interface, m) { + m.def("rtrn_mpty_valu", rtrn_mpty_valu); + m.def("rtrn_mpty_rref", rtrn_mpty_rref); + m.def("rtrn_mpty_cref", rtrn_mpty_cref); + m.def("rtrn_mpty_mref", rtrn_mpty_mref); + m.def("rtrn_mpty_cptr", rtrn_mpty_cptr); + m.def("rtrn_mpty_mptr", rtrn_mpty_mptr); + + m.def("pass_mpty_valu", pass_mpty_valu); + m.def("pass_mpty_rref", pass_mpty_rref); + m.def("pass_mpty_cref", pass_mpty_cref); + m.def("pass_mpty_mref", pass_mpty_mref); + m.def("pass_mpty_cptr", pass_mpty_cptr); + m.def("pass_mpty_mptr", pass_mpty_mptr); + + m.def("rtrn_mpty_shmp", rtrn_mpty_shmp); + m.def("rtrn_mpty_shcp", rtrn_mpty_shcp); + + m.def("pass_mpty_shmp", pass_mpty_shmp); + m.def("pass_mpty_shcp", pass_mpty_shcp); + + m.def("rtrn_mpty_uqmp", rtrn_mpty_uqmp); + m.def("rtrn_mpty_uqcp", rtrn_mpty_uqcp); + + m.def("pass_mpty_uqmp", pass_mpty_uqmp); + m.def("pass_mpty_uqcp", pass_mpty_uqcp); +} + +} // namespace type_caster_bare_interface +} // namespace pybind11_tests diff --git a/tests/test_type_caster_bare_interface.py b/tests/test_type_caster_bare_interface.py new file mode 100644 index 0000000000..5a19e1abcf --- /dev/null +++ b/tests/test_type_caster_bare_interface.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- + +from pybind11_tests import type_caster_bare_interface as m + + +def test_cast(): + assert m.rtrn_mpty_valu() == "cast_rref" + assert m.rtrn_mpty_rref() == "cast_rref" + assert m.rtrn_mpty_cref() == "cast_cref" + assert m.rtrn_mpty_mref() == "cast_mref" + assert m.rtrn_mpty_cptr() == "cast_cptr" + assert m.rtrn_mpty_mptr() == "cast_mptr" + + +def test_load(): + assert m.pass_mpty_valu(None) == "load_valu" + assert m.pass_mpty_rref(None) == "load_rref" + assert m.pass_mpty_cref(None) == "load_cref" + assert m.pass_mpty_mref(None) == "load_mref" + assert m.pass_mpty_cptr(None) == "load_cptr" + assert m.pass_mpty_mptr(None) == "load_mptr" + + +def test_cast_shared_ptr(): + assert m.rtrn_mpty_shmp() == "cast_shmp" + assert m.rtrn_mpty_shcp() == "cast_shcp" + + +def test_load_shared_ptr(): + assert m.pass_mpty_shmp(None) == "load_shmp" + assert m.pass_mpty_shcp(None) == "load_shcp" + + +def test_cast_unique_ptr(): + assert m.rtrn_mpty_uqmp() == "cast_uqmp" + assert m.rtrn_mpty_uqcp() == "cast_uqcp" + + +def test_load_unique_ptr(): + assert m.pass_mpty_uqmp(None) == "load_uqmp" + assert m.pass_mpty_uqcp(None) == "load_uqcp" From 96086c0f0bb03b4586c992969f927f7fee74123c Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 29 Jan 2021 14:00:26 -0800 Subject: [PATCH 2/3] Adding comment, simplifying naming, cmake addition. --- tests/CMakeLists.txt | 1 + tests/test_type_caster_bare_interface.cpp | 110 +++++++++++----------- tests/test_type_caster_bare_interface.py | 40 ++++---- 3 files changed, 78 insertions(+), 73 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9ff6c0dd9a..37026d82a6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -129,6 +129,7 @@ set(PYBIND11_TEST_FILES test_stl.cpp test_stl_binders.cpp test_tagbased_polymorphic.cpp + test_type_caster_bare_interface.cpp test_union.cpp test_virtual_functions.cpp) diff --git a/tests/test_type_caster_bare_interface.cpp b/tests/test_type_caster_bare_interface.cpp index 02b6281c2e..e334635a45 100644 --- a/tests/test_type_caster_bare_interface.cpp +++ b/tests/test_type_caster_bare_interface.cpp @@ -1,3 +1,7 @@ +// Systematically exercises the detail::type_caster<> interface. This is going a step in the +// direction of an integration test, to ensure multiple components of pybind11 work together +// correctly. It is also useful to show the type_caster<> interface virtually clutter-free. + #include "pybind11_tests.h" #include @@ -9,31 +13,31 @@ struct mpty {}; // clang-format off -mpty rtrn_mpty_valu() { mpty obj; return obj; } -mpty&& rtrn_mpty_rref() { static mpty obj; return std::move(obj); } -mpty const& rtrn_mpty_cref() { static mpty obj; return obj; } -mpty& rtrn_mpty_mref() { static mpty obj; return obj; } -mpty const* rtrn_mpty_cptr() { return new mpty; } -mpty* rtrn_mpty_mptr() { return new mpty; } +mpty rtrn_valu() { mpty obj; return obj; } +mpty&& rtrn_rref() { static mpty obj; return std::move(obj); } +mpty const& rtrn_cref() { static mpty obj; return obj; } +mpty& rtrn_mref() { static mpty obj; return obj; } +mpty const* rtrn_cptr() { return new mpty; } +mpty* rtrn_mptr() { return new mpty; } -const char* pass_mpty_valu(mpty) { return "load_valu"; } -const char* pass_mpty_rref(mpty&&) { return "load_rref"; } -const char* pass_mpty_cref(mpty const&) { return "load_cref"; } -const char* pass_mpty_mref(mpty&) { return "load_mref"; } -const char* pass_mpty_cptr(mpty const*) { return "load_cptr"; } -const char* pass_mpty_mptr(mpty*) { return "load_mptr"; } +const char* pass_valu(mpty) { return "load_valu"; } +const char* pass_rref(mpty&&) { return "load_rref"; } +const char* pass_cref(mpty const&) { return "load_cref"; } +const char* pass_mref(mpty&) { return "load_mref"; } +const char* pass_cptr(mpty const*) { return "load_cptr"; } +const char* pass_mptr(mpty*) { return "load_mptr"; } -std::shared_ptr rtrn_mpty_shmp() { return std::shared_ptr(new mpty); } -std::shared_ptr rtrn_mpty_shcp() { return std::shared_ptr(new mpty); } +std::shared_ptr rtrn_shmp() { return std::shared_ptr(new mpty); } +std::shared_ptr rtrn_shcp() { return std::shared_ptr(new mpty); } -const char* pass_mpty_shmp(std::shared_ptr) { return "load_shmp"; } -const char* pass_mpty_shcp(std::shared_ptr) { return "load_shcp"; } +const char* pass_shmp(std::shared_ptr) { return "load_shmp"; } +const char* pass_shcp(std::shared_ptr) { return "load_shcp"; } -std::unique_ptr rtrn_mpty_uqmp() { return std::unique_ptr(new mpty); } -std::unique_ptr rtrn_mpty_uqcp() { return std::unique_ptr(new mpty); } +std::unique_ptr rtrn_uqmp() { return std::unique_ptr(new mpty); } +std::unique_ptr rtrn_uqcp() { return std::unique_ptr(new mpty); } -const char* pass_mpty_uqmp(std::unique_ptr) { return "load_uqmp"; } -const char* pass_mpty_uqcp(std::unique_ptr) { return "load_uqcp"; } +const char* pass_uqmp(std::unique_ptr) { return "load_uqmp"; } +const char* pass_uqcp(std::unique_ptr) { return "load_uqcp"; } // clang-format on @@ -90,10 +94,10 @@ struct type_caster { // clang-format off - operator mpty() { return rtrn_mpty_valu(); } - operator mpty&&() && { return rtrn_mpty_rref(); } - operator mpty const&() { return rtrn_mpty_cref(); } - operator mpty&() { return rtrn_mpty_mref(); } + operator mpty() { return rtrn_valu(); } + operator mpty&&() && { return rtrn_rref(); } + operator mpty const&() { return rtrn_cref(); } + operator mpty&() { return rtrn_mref(); } operator mpty const*() { static mpty obj; return &obj; } operator mpty*() { static mpty obj; return &obj; } @@ -115,7 +119,7 @@ struct type_caster> { template using cast_op_type = std::shared_ptr; - operator std::shared_ptr() { return rtrn_mpty_shmp(); } + operator std::shared_ptr() { return rtrn_shmp(); } bool load(handle /*src*/, bool /*convert*/) { return true; } }; @@ -133,7 +137,7 @@ struct type_caster> { template using cast_op_type = std::shared_ptr; - operator std::shared_ptr() { return rtrn_mpty_shcp(); } + operator std::shared_ptr() { return rtrn_shcp(); } bool load(handle /*src*/, bool /*convert*/) { return true; } }; @@ -150,7 +154,7 @@ struct type_caster> { template using cast_op_type = std::unique_ptr; - operator std::unique_ptr() { return rtrn_mpty_uqmp(); } + operator std::unique_ptr() { return rtrn_uqmp(); } bool load(handle /*src*/, bool /*convert*/) { return true; } }; @@ -168,7 +172,7 @@ struct type_caster> { template using cast_op_type = std::unique_ptr; - operator std::unique_ptr() { return rtrn_mpty_uqcp(); } + operator std::unique_ptr() { return rtrn_uqcp(); } bool load(handle /*src*/, bool /*convert*/) { return true; } }; @@ -180,31 +184,31 @@ namespace pybind11_tests { namespace type_caster_bare_interface { TEST_SUBMODULE(type_caster_bare_interface, m) { - m.def("rtrn_mpty_valu", rtrn_mpty_valu); - m.def("rtrn_mpty_rref", rtrn_mpty_rref); - m.def("rtrn_mpty_cref", rtrn_mpty_cref); - m.def("rtrn_mpty_mref", rtrn_mpty_mref); - m.def("rtrn_mpty_cptr", rtrn_mpty_cptr); - m.def("rtrn_mpty_mptr", rtrn_mpty_mptr); - - m.def("pass_mpty_valu", pass_mpty_valu); - m.def("pass_mpty_rref", pass_mpty_rref); - m.def("pass_mpty_cref", pass_mpty_cref); - m.def("pass_mpty_mref", pass_mpty_mref); - m.def("pass_mpty_cptr", pass_mpty_cptr); - m.def("pass_mpty_mptr", pass_mpty_mptr); - - m.def("rtrn_mpty_shmp", rtrn_mpty_shmp); - m.def("rtrn_mpty_shcp", rtrn_mpty_shcp); - - m.def("pass_mpty_shmp", pass_mpty_shmp); - m.def("pass_mpty_shcp", pass_mpty_shcp); - - m.def("rtrn_mpty_uqmp", rtrn_mpty_uqmp); - m.def("rtrn_mpty_uqcp", rtrn_mpty_uqcp); - - m.def("pass_mpty_uqmp", pass_mpty_uqmp); - m.def("pass_mpty_uqcp", pass_mpty_uqcp); + m.def("rtrn_valu", rtrn_valu); + m.def("rtrn_rref", rtrn_rref); + m.def("rtrn_cref", rtrn_cref); + m.def("rtrn_mref", rtrn_mref); + m.def("rtrn_cptr", rtrn_cptr); + m.def("rtrn_mptr", rtrn_mptr); + + m.def("pass_valu", pass_valu); + m.def("pass_rref", pass_rref); + m.def("pass_cref", pass_cref); + m.def("pass_mref", pass_mref); + m.def("pass_cptr", pass_cptr); + m.def("pass_mptr", pass_mptr); + + m.def("rtrn_shmp", rtrn_shmp); + m.def("rtrn_shcp", rtrn_shcp); + + m.def("pass_shmp", pass_shmp); + m.def("pass_shcp", pass_shcp); + + m.def("rtrn_uqmp", rtrn_uqmp); + m.def("rtrn_uqcp", rtrn_uqcp); + + m.def("pass_uqmp", pass_uqmp); + m.def("pass_uqcp", pass_uqcp); } } // namespace type_caster_bare_interface diff --git a/tests/test_type_caster_bare_interface.py b/tests/test_type_caster_bare_interface.py index 5a19e1abcf..a427244dbc 100644 --- a/tests/test_type_caster_bare_interface.py +++ b/tests/test_type_caster_bare_interface.py @@ -4,38 +4,38 @@ def test_cast(): - assert m.rtrn_mpty_valu() == "cast_rref" - assert m.rtrn_mpty_rref() == "cast_rref" - assert m.rtrn_mpty_cref() == "cast_cref" - assert m.rtrn_mpty_mref() == "cast_mref" - assert m.rtrn_mpty_cptr() == "cast_cptr" - assert m.rtrn_mpty_mptr() == "cast_mptr" + assert m.rtrn_valu() == "cast_rref" + assert m.rtrn_rref() == "cast_rref" + assert m.rtrn_cref() == "cast_cref" + assert m.rtrn_mref() == "cast_mref" + assert m.rtrn_cptr() == "cast_cptr" + assert m.rtrn_mptr() == "cast_mptr" def test_load(): - assert m.pass_mpty_valu(None) == "load_valu" - assert m.pass_mpty_rref(None) == "load_rref" - assert m.pass_mpty_cref(None) == "load_cref" - assert m.pass_mpty_mref(None) == "load_mref" - assert m.pass_mpty_cptr(None) == "load_cptr" - assert m.pass_mpty_mptr(None) == "load_mptr" + assert m.pass_valu(None) == "load_valu" + assert m.pass_rref(None) == "load_rref" + assert m.pass_cref(None) == "load_cref" + assert m.pass_mref(None) == "load_mref" + assert m.pass_cptr(None) == "load_cptr" + assert m.pass_mptr(None) == "load_mptr" def test_cast_shared_ptr(): - assert m.rtrn_mpty_shmp() == "cast_shmp" - assert m.rtrn_mpty_shcp() == "cast_shcp" + assert m.rtrn_shmp() == "cast_shmp" + assert m.rtrn_shcp() == "cast_shcp" def test_load_shared_ptr(): - assert m.pass_mpty_shmp(None) == "load_shmp" - assert m.pass_mpty_shcp(None) == "load_shcp" + assert m.pass_shmp(None) == "load_shmp" + assert m.pass_shcp(None) == "load_shcp" def test_cast_unique_ptr(): - assert m.rtrn_mpty_uqmp() == "cast_uqmp" - assert m.rtrn_mpty_uqcp() == "cast_uqcp" + assert m.rtrn_uqmp() == "cast_uqmp" + assert m.rtrn_uqcp() == "cast_uqcp" def test_load_unique_ptr(): - assert m.pass_mpty_uqmp(None) == "load_uqmp" - assert m.pass_mpty_uqcp(None) == "load_uqcp" + assert m.pass_uqmp(None) == "load_uqmp" + assert m.pass_uqcp(None) == "load_uqcp" From 5d21d8a74f43b6addef44541533c3a6e939ba377 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 8 Mar 2021 11:38:40 -0800 Subject: [PATCH 3/3] Tracing CpCtor, MvCtor, removing smart-pointer casters, renaming, more comments. --- tests/test_type_caster_bare_interface.cpp | 201 ++++++---------------- tests/test_type_caster_bare_interface.py | 67 ++++---- 2 files changed, 87 insertions(+), 181 deletions(-) diff --git a/tests/test_type_caster_bare_interface.cpp b/tests/test_type_caster_bare_interface.cpp index e334635a45..18d6888801 100644 --- a/tests/test_type_caster_bare_interface.cpp +++ b/tests/test_type_caster_bare_interface.cpp @@ -2,42 +2,40 @@ // direction of an integration test, to ensure multiple components of pybind11 work together // correctly. It is also useful to show the type_caster<> interface virtually clutter-free. +// The entire type_caster load logic is intentionally omitted. The only purpose of this test is to +// trace the behavior of the `static handle cast()` functions and the type_caster `operator`s. +// Variable names are intentionally terse, to not distract from the more important function +// signatures: valu(e), ref(erence), ptr (pointer), r = rvalue, m = mutable, c = const. + #include "pybind11_tests.h" -#include +#include namespace pybind11_tests { namespace type_caster_bare_interface { -struct mpty {}; +struct atyp { // Short for "any type". + std::string trace; + atyp() : trace("default") {} + atyp(atyp const &other) { trace = other.trace + "_CpCtor"; } + atyp(atyp &&other) { trace = other.trace + "_MvCtor"; } +}; // clang-format off -mpty rtrn_valu() { mpty obj; return obj; } -mpty&& rtrn_rref() { static mpty obj; return std::move(obj); } -mpty const& rtrn_cref() { static mpty obj; return obj; } -mpty& rtrn_mref() { static mpty obj; return obj; } -mpty const* rtrn_cptr() { return new mpty; } -mpty* rtrn_mptr() { return new mpty; } - -const char* pass_valu(mpty) { return "load_valu"; } -const char* pass_rref(mpty&&) { return "load_rref"; } -const char* pass_cref(mpty const&) { return "load_cref"; } -const char* pass_mref(mpty&) { return "load_mref"; } -const char* pass_cptr(mpty const*) { return "load_cptr"; } -const char* pass_mptr(mpty*) { return "load_mptr"; } - -std::shared_ptr rtrn_shmp() { return std::shared_ptr(new mpty); } -std::shared_ptr rtrn_shcp() { return std::shared_ptr(new mpty); } +atyp rtrn_valu() { static atyp obj; obj.trace = "valu"; return obj; } +atyp&& rtrn_rref() { static atyp obj; obj.trace = "rref"; return std::move(obj); } +atyp const& rtrn_cref() { static atyp obj; obj.trace = "cref"; return obj; } +atyp& rtrn_mref() { static atyp obj; obj.trace = "mref"; return obj; } +atyp const* rtrn_cptr() { static atyp obj; obj.trace = "cptr"; return &obj; } +atyp* rtrn_mptr() { static atyp obj; obj.trace = "mptr"; return &obj; } -const char* pass_shmp(std::shared_ptr) { return "load_shmp"; } -const char* pass_shcp(std::shared_ptr) { return "load_shcp"; } - -std::unique_ptr rtrn_uqmp() { return std::unique_ptr(new mpty); } -std::unique_ptr rtrn_uqcp() { return std::unique_ptr(new mpty); } - -const char* pass_uqmp(std::unique_ptr) { return "load_uqmp"; } -const char* pass_uqcp(std::unique_ptr) { return "load_uqcp"; } +std::string pass_valu(atyp obj) { return "pass_valu:" + obj.trace; } +std::string pass_rref(atyp&& obj) { return "pass_rref:" + obj.trace; } +std::string pass_cref(atyp const& obj) { return "pass_cref:" + obj.trace; } +std::string pass_mref(atyp& obj) { return "pass_mref:" + obj.trace; } +std::string pass_cptr(atyp const* obj) { return "pass_cptr:" + obj->trace; } +std::string pass_mptr(atyp* obj) { return "pass_mptr:" + obj->trace; } // clang-format on @@ -50,140 +48,68 @@ namespace detail { using namespace pybind11_tests::type_caster_bare_interface; template <> -struct type_caster { - static constexpr auto name = _(); +struct type_caster { + static constexpr auto name = _(); - // static handle cast(mpty, ...) + // static handle cast(atyp, ...) // is redundant (leads to ambiguous overloads). - static handle cast(mpty && /*src*/, return_value_policy /*policy*/, handle /*parent*/) { - return str("cast_rref").release(); + static handle cast(atyp &&src, return_value_policy /*policy*/, handle /*parent*/) { + return str("cast_rref:" + src.trace).release(); } - static handle cast(mpty const & /*src*/, return_value_policy /*policy*/, handle /*parent*/) { - return str("cast_cref").release(); + static handle cast(atyp const &src, return_value_policy /*policy*/, handle /*parent*/) { + return str("cast_cref:" + src.trace).release(); } - static handle cast(mpty & /*src*/, return_value_policy /*policy*/, handle /*parent*/) { - return str("cast_mref").release(); + static handle cast(atyp &src, return_value_policy /*policy*/, handle /*parent*/) { + return str("cast_mref:" + src.trace).release(); } - static handle cast(mpty const *src, return_value_policy /*policy*/, handle /*parent*/) { - delete src; - return str("cast_cptr").release(); + static handle cast(atyp const *src, return_value_policy /*policy*/, handle /*parent*/) { + return str("cast_cptr:" + src->trace).release(); } - static handle cast(mpty *src, return_value_policy /*policy*/, handle /*parent*/) { - delete src; - return str("cast_mptr").release(); + static handle cast(atyp *src, return_value_policy /*policy*/, handle /*parent*/) { + return str("cast_mptr:" + src->trace).release(); } template using cast_op_type = conditional_t< - std::is_same, mpty const *>::value, - mpty const *, + std::is_same, atyp const *>::value, + atyp const *, conditional_t< - std::is_same, mpty *>::value, - mpty *, + std::is_same, atyp *>::value, + atyp *, conditional_t< - std::is_same::value, - mpty const &, - conditional_t::value, - mpty &, - conditional_t::value, mpty &&, mpty>>>>>; + std::is_same::value, + atyp const &, + conditional_t::value, + atyp &, + conditional_t::value, atyp &&, atyp>>>>>; // clang-format off - operator mpty() { return rtrn_valu(); } - operator mpty&&() && { return rtrn_rref(); } - operator mpty const&() { return rtrn_cref(); } - operator mpty&() { return rtrn_mref(); } - operator mpty const*() { static mpty obj; return &obj; } - operator mpty*() { static mpty obj; return &obj; } + operator atyp() { static atyp obj; obj.trace = "valu"; return obj; } + operator atyp&&() { static atyp obj; obj.trace = "rref"; return std::move(obj); } + operator atyp const&() { static atyp obj; obj.trace = "cref"; return obj; } + operator atyp&() { static atyp obj; obj.trace = "mref"; return obj; } + operator atyp const*() { static atyp obj; obj.trace = "cptr"; return &obj; } + operator atyp*() { static atyp obj; obj.trace = "mptr"; return &obj; } // clang-format on - bool load(handle /*src*/, bool /*convert*/) { return true; } -}; - -template <> -struct type_caster> { - static constexpr auto name = _>(); - - static handle cast(const std::shared_ptr & /*src*/, - return_value_policy /*policy*/, - handle /*parent*/) { - return str("cast_shmp").release(); - } - - template - using cast_op_type = std::shared_ptr; - - operator std::shared_ptr() { return rtrn_shmp(); } - - bool load(handle /*src*/, bool /*convert*/) { return true; } -}; - -template <> -struct type_caster> { - static constexpr auto name = _>(); - - static handle cast(const std::shared_ptr & /*src*/, - return_value_policy /*policy*/, - handle /*parent*/) { - return str("cast_shcp").release(); - } - - template - using cast_op_type = std::shared_ptr; - - operator std::shared_ptr() { return rtrn_shcp(); } - - bool load(handle /*src*/, bool /*convert*/) { return true; } -}; - -template <> -struct type_caster> { - static constexpr auto name = _>(); - - static handle - cast(std::unique_ptr && /*src*/, return_value_policy /*policy*/, handle /*parent*/) { - return str("cast_uqmp").release(); - } - - template - using cast_op_type = std::unique_ptr; - - operator std::unique_ptr() { return rtrn_uqmp(); } - - bool load(handle /*src*/, bool /*convert*/) { return true; } -}; - -template <> -struct type_caster> { - static constexpr auto name = _>(); - - static handle cast(std::unique_ptr && /*src*/, - return_value_policy /*policy*/, - handle /*parent*/) { - return str("cast_uqcp").release(); - } - - template - using cast_op_type = std::unique_ptr; - - operator std::unique_ptr() { return rtrn_uqcp(); } - + // The entire load logic is intentionally omitted. bool load(handle /*src*/, bool /*convert*/) { return true; } }; } // namespace detail } // namespace pybind11 -namespace pybind11_tests { -namespace type_caster_bare_interface { - TEST_SUBMODULE(type_caster_bare_interface, m) { + namespace py = pybind11; + using namespace pybind11_tests::type_caster_bare_interface; + m.def("rtrn_valu", rtrn_valu); m.def("rtrn_rref", rtrn_rref); m.def("rtrn_cref", rtrn_cref); @@ -197,19 +123,4 @@ TEST_SUBMODULE(type_caster_bare_interface, m) { m.def("pass_mref", pass_mref); m.def("pass_cptr", pass_cptr); m.def("pass_mptr", pass_mptr); - - m.def("rtrn_shmp", rtrn_shmp); - m.def("rtrn_shcp", rtrn_shcp); - - m.def("pass_shmp", pass_shmp); - m.def("pass_shcp", pass_shcp); - - m.def("rtrn_uqmp", rtrn_uqmp); - m.def("rtrn_uqcp", rtrn_uqcp); - - m.def("pass_uqmp", pass_uqmp); - m.def("pass_uqcp", pass_uqcp); } - -} // namespace type_caster_bare_interface -} // namespace pybind11_tests diff --git a/tests/test_type_caster_bare_interface.py b/tests/test_type_caster_bare_interface.py index a427244dbc..fd27e1ae92 100644 --- a/tests/test_type_caster_bare_interface.py +++ b/tests/test_type_caster_bare_interface.py @@ -1,41 +1,36 @@ # -*- coding: utf-8 -*- +import re -from pybind11_tests import type_caster_bare_interface as m - - -def test_cast(): - assert m.rtrn_valu() == "cast_rref" - assert m.rtrn_rref() == "cast_rref" - assert m.rtrn_cref() == "cast_cref" - assert m.rtrn_mref() == "cast_mref" - assert m.rtrn_cptr() == "cast_cptr" - assert m.rtrn_mptr() == "cast_mptr" - - -def test_load(): - assert m.pass_valu(None) == "load_valu" - assert m.pass_rref(None) == "load_rref" - assert m.pass_cref(None) == "load_cref" - assert m.pass_mref(None) == "load_mref" - assert m.pass_cptr(None) == "load_cptr" - assert m.pass_mptr(None) == "load_mptr" - +import pytest -def test_cast_shared_ptr(): - assert m.rtrn_shmp() == "cast_shmp" - assert m.rtrn_shcp() == "cast_shcp" - - -def test_load_shared_ptr(): - assert m.pass_shmp(None) == "load_shmp" - assert m.pass_shcp(None) == "load_shcp" - - -def test_cast_unique_ptr(): - assert m.rtrn_uqmp() == "cast_uqmp" - assert m.rtrn_uqcp() == "cast_uqcp" +from pybind11_tests import type_caster_bare_interface as m -def test_load_unique_ptr(): - assert m.pass_uqmp(None) == "load_uqmp" - assert m.pass_uqcp(None) == "load_uqcp" +@pytest.mark.parametrize( + "rtrn_f, expected", + [ + (m.rtrn_valu, "cast_rref:valu_CpCtor"), + (m.rtrn_rref, "cast_rref:rref"), + (m.rtrn_cref, "cast_cref:cref"), + (m.rtrn_mref, "cast_mref:mref"), + (m.rtrn_cptr, "cast_cptr:cptr"), + (m.rtrn_mptr, "cast_mptr:mptr"), + ], +) +def test_cast(rtrn_f, expected): + assert re.match(expected, rtrn_f()) + + +@pytest.mark.parametrize( + "pass_f, expected", + [ + (m.pass_valu, "pass_valu:rref_MvCtor"), + (m.pass_rref, "pass_rref:rref"), + (m.pass_cref, "pass_cref:cref"), + (m.pass_mref, "pass_mref:mref"), + (m.pass_cptr, "pass_cptr:cptr"), + (m.pass_mptr, "pass_mptr:mptr"), + ], +) +def test_operator(pass_f, expected): + assert re.match(expected, pass_f(None))