@@ -40,6 +40,9 @@ enum cast_flags : uint8_t {
4040
4141 // Don't accept 'None' Python objects in the base class caster
4242 none_disallowed = (1 << 2 ),
43+
44+ // Indicates that this cast is performed by nb::cast or nb::try_cast
45+ manual = (1 << 3 )
4346};
4447
4548/* *
@@ -411,53 +414,86 @@ template <typename Type_> struct type_caster_base : type_caster_base_tag {
411414template <typename Type, typename SFINAE>
412415struct type_caster : type_caster_base<Type> { };
413416
414- NAMESPACE_END (detail)
417+ template <bool Convert, typename T>
418+ T cast_impl (handle h) {
419+ using Caster = detail::make_caster<T>;
415420
416- template <typename T, typename Derived>
417- bool try_cast(const detail::api<Derived> &value, T &out, bool convert = true ) noexcept {
421+ static_assert (
422+ !(std::is_reference_v<T> || std::is_pointer_v<T>) ||
423+ detail::is_base_caster_v<Caster> ||
424+ std::is_same_v<const char *, T>,
425+ " nanobind::cast(): cannot return a reference to a temporary." );
426+
427+ Caster caster;
428+ bool rv;
429+ if constexpr (Convert) {
430+ cleanup_list cleanup (nullptr );
431+ rv = caster.from_python (h.ptr (),
432+ ((uint8_t ) cast_flags::convert) |
433+ ((uint8_t ) cast_flags::manual),
434+ &cleanup);
435+ cleanup.release (); // 'from_python' is 'noexcept', so this always runs
436+ } else {
437+ rv = caster.from_python (h.ptr (), (uint8_t ) cast_flags::manual, nullptr );
438+ }
439+
440+ if (!rv)
441+ detail::raise_cast_error ();
442+ return caster.operator detail::cast_t <T>();
443+ }
444+
445+ template <bool Convert, typename T>
446+ bool try_cast_impl (handle h, T &out) noexcept {
418447 using Caster = detail::make_caster<T>;
419448
420449 static_assert (!std::is_same_v<const char *, T>,
421450 " nanobind::try_cast(): cannot return a reference to a temporary." );
422451
423452 Caster caster;
424- if (caster.from_python (value.derived ().ptr (),
425- convert ? (uint8_t ) detail::cast_flags::convert
426- : (uint8_t ) 0 , nullptr )) {
453+ bool rv;
454+ if constexpr (Convert) {
455+ cleanup_list cleanup (nullptr );
456+ rv = caster.from_python (h.ptr (),
457+ ((uint8_t ) cast_flags::convert) |
458+ ((uint8_t ) cast_flags::manual),
459+ &cleanup);
460+ cleanup.release (); // 'from_python' is 'noexcept', so this always runs
461+ } else {
462+ rv = caster.from_python (h.ptr (), (uint8_t ) cast_flags::manual, nullptr );
463+ }
464+
465+ if (rv) {
427466 try {
428467 out = caster.operator detail::cast_t <T>();
429468 return true ;
430- } catch (const builtin_exception&) {
431- return false ;
432- }
469+ } catch (const builtin_exception&) { }
433470 }
434471
435472 return false ;
436473}
437474
475+ NAMESPACE_END (detail)
476+
438477template <typename T, typename Derived>
439- T cast (const detail::api<Derived> &value, bool convert = true ) {
478+ NB_INLINE T cast(const detail::api<Derived> &value, bool convert = true ) {
440479 if constexpr (std::is_same_v<T, void >) {
441480 return ;
442481 } else {
443- using Caster = detail::make_caster<T>;
444-
445- static_assert (
446- !(std::is_reference_v<T> || std::is_pointer_v<T>) ||
447- detail::is_base_caster_v<Caster> ||
448- std::is_same_v<const char *, T>,
449- " nanobind::cast(): cannot return a reference to a temporary." );
450-
451- Caster caster;
452- if (!caster.from_python (value.derived ().ptr (),
453- convert ? (uint8_t ) detail::cast_flags::convert
454- : (uint8_t ) 0 , nullptr ))
455- detail::raise_cast_error ();
456-
457- return caster.operator detail::cast_t <T>();
482+ if (convert)
483+ return detail::cast_impl<true , T>(value);
484+ else
485+ return detail::cast_impl<false , T>(value);
458486 }
459487}
460488
489+ template <typename T, typename Derived>
490+ NB_INLINE bool try_cast (const detail::api<Derived> &value, T &out, bool convert = true ) noexcept {
491+ if (convert)
492+ return detail::try_cast_impl<true , T>(value, out);
493+ else
494+ return detail::try_cast_impl<false , T>(value, out);
495+ }
496+
461497template <typename T>
462498object cast (T &&value, rv_policy policy = rv_policy::automatic_reference) {
463499 handle h = detail::make_caster<T>::from_cpp ((detail::forward_t <T>) value,
0 commit comments