1/* 2 tests/test_tagbased_polymorphic.cpp -- test of polymorphic_type_hook 3 4 Copyright (c) 2018 Hudson River Trading LLC <opensource@hudson-trading.com> 5 6 All rights reserved. Use of this source code is governed by a 7 BSD-style license that can be found in the LICENSE file. 8*/ 9 10#include "pybind11_tests.h" 11#include <pybind11/stl.h> 12 13struct Animal 14{ 15 enum class Kind { 16 Unknown = 0, 17 Dog = 100, Labrador, Chihuahua, LastDog = 199, 18 Cat = 200, Panther, LastCat = 299 19 }; 20 static const std::type_info* type_of_kind(Kind kind); 21 static std::string name_of_kind(Kind kind); 22 23 const Kind kind; 24 const std::string name; 25 26 protected: 27 Animal(const std::string& _name, Kind _kind) 28 : kind(_kind), name(_name) 29 {} 30}; 31 32struct Dog : Animal 33{ 34 Dog(const std::string& _name, Kind _kind = Kind::Dog) : Animal(_name, _kind) {} 35 std::string bark() const { return name_of_kind(kind) + " " + name + " goes " + sound; } 36 std::string sound = "WOOF!"; 37}; 38 39struct Labrador : Dog 40{ 41 Labrador(const std::string& _name, int _excitement = 9001) 42 : Dog(_name, Kind::Labrador), excitement(_excitement) {} 43 int excitement; 44}; 45 46struct Chihuahua : Dog 47{ 48 Chihuahua(const std::string& _name) : Dog(_name, Kind::Chihuahua) { sound = "iyiyiyiyiyi"; } 49 std::string bark() const { return Dog::bark() + " and runs in circles"; } 50}; 51 52struct Cat : Animal 53{ 54 Cat(const std::string& _name, Kind _kind = Kind::Cat) : Animal(_name, _kind) {} 55 std::string purr() const { return "mrowr"; } 56}; 57 58struct Panther : Cat 59{ 60 Panther(const std::string& _name) : Cat(_name, Kind::Panther) {} 61 std::string purr() const { return "mrrrRRRRRR"; } 62}; 63 64std::vector<std::unique_ptr<Animal>> create_zoo() 65{ 66 std::vector<std::unique_ptr<Animal>> ret; 67 ret.emplace_back(new Labrador("Fido", 15000)); 68 69 // simulate some new type of Dog that the Python bindings 70 // haven't been updated for; it should still be considered 71 // a Dog, not just an Animal. 72 ret.emplace_back(new Dog("Ginger", Dog::Kind(150))); 73 74 ret.emplace_back(new Chihuahua("Hertzl")); 75 ret.emplace_back(new Cat("Tiger", Cat::Kind::Cat)); 76 ret.emplace_back(new Panther("Leo")); 77 return ret; 78} 79 80const std::type_info* Animal::type_of_kind(Kind kind) 81{ 82 switch (kind) { 83 case Kind::Unknown: break; 84 85 case Kind::Dog: break; 86 case Kind::Labrador: return &typeid(Labrador); 87 case Kind::Chihuahua: return &typeid(Chihuahua); 88 case Kind::LastDog: break; 89 90 case Kind::Cat: break; 91 case Kind::Panther: return &typeid(Panther); 92 case Kind::LastCat: break; 93 } 94 95 if (kind >= Kind::Dog && kind <= Kind::LastDog) return &typeid(Dog); 96 if (kind >= Kind::Cat && kind <= Kind::LastCat) return &typeid(Cat); 97 return nullptr; 98} 99 100std::string Animal::name_of_kind(Kind kind) 101{ 102 std::string raw_name = type_of_kind(kind)->name(); 103 py::detail::clean_type_id(raw_name); 104 return raw_name; 105} 106 107namespace pybind11 { 108 template <typename itype> 109 struct polymorphic_type_hook<itype, detail::enable_if_t<std::is_base_of<Animal, itype>::value>> 110 { 111 static const void *get(const itype *src, const std::type_info*& type) 112 { type = src ? Animal::type_of_kind(src->kind) : nullptr; return src; } 113 }; 114} 115 116TEST_SUBMODULE(tagbased_polymorphic, m) { 117 py::class_<Animal>(m, "Animal") 118 .def_readonly("name", &Animal::name); 119 py::class_<Dog, Animal>(m, "Dog") 120 .def(py::init<std::string>()) 121 .def_readwrite("sound", &Dog::sound) 122 .def("bark", &Dog::bark); 123 py::class_<Labrador, Dog>(m, "Labrador") 124 .def(py::init<std::string, int>(), "name"_a, "excitement"_a = 9001) 125 .def_readwrite("excitement", &Labrador::excitement); 126 py::class_<Chihuahua, Dog>(m, "Chihuahua") 127 .def(py::init<std::string>()) 128 .def("bark", &Chihuahua::bark); 129 py::class_<Cat, Animal>(m, "Cat") 130 .def(py::init<std::string>()) 131 .def("purr", &Cat::purr); 132 py::class_<Panther, Cat>(m, "Panther") 133 .def(py::init<std::string>()) 134 .def("purr", &Panther::purr); 135 m.def("create_zoo", &create_zoo); 136}; 137