#pragma once #include "instance.h" namespace pkbind { template constexpr inline bool is_string_v = std::is_same_v || std::is_same_v || std::is_same_v; /// The `type_caster` class is responsible for converting between Python objects and C++ objects. /// /// The static method `type_caster::cast(...)` is used to convert a C++ object to a Python object. /// If the conversion fails, an exception is thrown. /// /// The method `type_caster::load(...)` is used to try to convert a Python object to a C++ object. /// If the conversion is successful, it returns true, and you can then call `type_caster::value()` /// to access the resulting C++ object. If the conversion fails, it returns false. /// /// NOTE: The type T could be a reference type or a pointer type. What is the lifetime of the reference or pointer? /// It depends on the referenced type. For some types, such as bool, int, float, etc., the loaded value is stored /// in the type_caster itself, so the lifetime of the reference is no longer than the lifetime of the type_caster /// object. For other user-registered types, the lifetime of the reference is the same as the corresponding Python /// object. A static variable `is_temporary_v` is used to indicate whether the loaded value is temporary or not. template struct type_caster { T* data; static_assert(!std::is_pointer_v, "type caster for pointer type must be specialized."); static_assert(!std::is_reference_v, "type caster for reference type must be specialized."); template static object cast(U&& value, return_value_policy policy, handle parent) { // TODO: support implicit cast return instance::create(type::of(), std::forward(value), parent, policy); } bool load(handle src, bool convert) { if(isinstance(src)) { auto& i = *static_cast(py_touserdata(src.ptr())); data = &i.as(); return true; } return false; } T& value() { return *data; } constexpr inline static bool is_temporary_v = false; }; template <> struct type_caster { bool data; static object cast(bool src, return_value_policy, handle) { return bool_(src); } bool load(handle src, bool) { if(isinstance(src)) { data = py_tobool(src.ptr()); return true; } return false; } bool& value() { return data; } constexpr inline static bool is_temporary_v = true; }; template struct type_caster>> { T data; static object cast(T src, return_value_policy, handle) { return int_(src); } bool load(handle src, bool) { if(isinstance(src)) { data = static_cast(py_toint(src.ptr())); return true; } return false; } T& value() { return data; } constexpr inline static bool is_temporary_v = true; }; template struct type_caster>> { T data; static object cast(T src, return_value_policy, handle) { return float_(src); } bool load(handle src, bool convert) { if(isinstance(src)) { data = static_cast(py_tofloat(src.ptr())); return true; } if(convert && isinstance(src)) { data = static_cast(py_toint(src.ptr())); return true; } return false; } T& value() { return data; } constexpr inline static bool is_temporary_v = true; }; template struct type_caster>> { T data; template static object cast(U&& src, return_value_policy, handle) { return str(std::forward(src)); } bool load(handle src, bool) { if(isinstance(src)) { data = py_tostr(src.ptr()); return true; } return false; } T& value() { return data; } constexpr inline static bool is_temporary_v = true; }; template struct type_caster>> { T data; template static object cast(U&& src, return_value_policy, handle) { return object(std::forward(src)); } bool load(handle src, bool) { if(isinstance(src)) { data = T(src.ptr(), object::realloc_t{}); return true; } return false; } T& value() { return data; } constexpr inline static bool is_temporary_v = true; }; template struct type_caster || std::is_reference_v>> { using underlying = std::remove_cv_t, std::remove_pointer_t, std::remove_reference_t>>; type_caster caster; template static object cast(U&& value, return_value_policy policy, handle parent) { return type_caster::cast(std::forward(value), policy, parent); } bool load(handle src, bool convert) { return caster.load(src, convert); } T value() { if constexpr(std::is_pointer_v) { return &caster.value(); } else { return caster.value(); } } constexpr inline static bool is_temporary_v = type_caster::is_temporary_v; }; } // namespace pkbind