32
32
# include < variant>
33
33
#endif
34
34
35
+ #ifdef __cpp_lib_expected
36
+ # include < expected>
37
+ #endif
38
+
35
39
PYBIND11_NAMESPACE_BEGIN (PYBIND11_NAMESPACE)
36
40
PYBIND11_NAMESPACE_BEGIN(detail)
37
41
@@ -424,6 +428,47 @@ struct variant_caster<V<Ts...>> {
424
428
+ const_name(" ]" ));
425
429
};
426
430
431
+ // / Generic expected caster
432
+ template <typename E>
433
+ struct expected_caster ;
434
+
435
+ template <template <typename , typename > class E , typename TValue, typename TError>
436
+ struct expected_caster <E<TValue, TError>> {
437
+ using expected_type = E<TValue, TError>;
438
+
439
+ // I'm not sure what we should call this, as we never actually hold it
440
+ // on the python side, it's exclusively deconstructed. In our case, we really
441
+ // only care about the conversion from C++ to Python.
442
+ // Maybe something like `Union[TValue, TError]`?
443
+ PYBIND11_TYPE_CASTER (expected_type, pybind11::detail::const_name(" expected" ));
444
+
445
+ // load() is not implemented - we are only interested in unwrapping expected
446
+ // types from C++, not re-wrapping them.
447
+
448
+ // This is templated so that it takes a universal reference rather than an
449
+ // rvalue reference.
450
+ static pybind11::handle cast (std::same_as<expected_type> auto &&src,
451
+ pybind11::return_value_policy policy,
452
+ pybind11::handle parent) {
453
+ if (src.has_value ()) {
454
+ return pybind11::detail::make_caster<TValue>::cast (
455
+ std::forward<expected_type>(src).value (), policy, parent);
456
+ } else {
457
+ // The goal here is to defer to __repr__ for consistent formatting with
458
+ // Python
459
+ if constexpr (std::same_as<TError, std::string>) {
460
+ // Optimize in this case, no need to convert to python to get its
461
+ // representation
462
+ throw std::runtime_error (std::forward<expected_type>(src).error ());
463
+ } else {
464
+ auto str = pybind11::detail::make_caster<TError>::cast (
465
+ std::forward<expected_type>(src).error (), policy, parent);
466
+ throw std::runtime_error (pybind11::repr (std::move (str)));
467
+ }
468
+ }
469
+ }
470
+ };
471
+
427
472
#if defined(PYBIND11_HAS_VARIANT)
428
473
template <typename ... Ts>
429
474
struct type_caster <std::variant<Ts...>> : variant_caster<std::variant<Ts...>> {};
@@ -432,6 +477,12 @@ template <>
432
477
struct type_caster <std::monostate> : public void_caster<std::monostate> {};
433
478
#endif
434
479
480
+ #ifdef __cpp_lib_expected
481
+ template <typename TValue, typename TError>
482
+ struct pybind11 ::detail::type_caster<std::expected<TValue, TError>>
483
+ : expected_caster<std::expected<TValue, TError>> {};
484
+ #endif
485
+
435
486
PYBIND11_NAMESPACE_END (detail)
436
487
437
488
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
0 commit comments