Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ set(_tvm_ffi_objs_sources
set(_tvm_ffi_extra_objs_sources
"${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/structural_equal.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/structural_hash.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/structural_visit.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/visit_error_context.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/json_parser.cc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/json_writer.cc"
Expand Down
2 changes: 2 additions & 0 deletions include/tvm/ffi/c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ typedef enum {
kTVMFFIList = 75,
/*! \brief Dict object. */
kTVMFFIDict = 76,
/*! \brief Structural visit interrupt object. */
kTVMFFIVisitInterrupt = 77,
//----------------------------------------------------------------
// more complex objects
//----------------------------------------------------------------
Expand Down
78 changes: 78 additions & 0 deletions include/tvm/ffi/expected.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ template <typename E>
Unexpected(E) -> Unexpected<E>;
#endif

namespace details {

struct ExpectedUnsafe;

} // namespace details

/*!
* \brief Expected<T> provides exception-free error handling for FFI functions.
*
Expand Down Expand Up @@ -113,6 +119,9 @@ class Expected {
// NOLINTNEXTLINE(google-explicit-constructor,runtime/explicit)
Expected(Unexpected<E> unexpected) : data_(Any(std::move(unexpected).error())) {}

/*! \brief Return the raw stored type index. */
TVM_FFI_INLINE int32_t type_index() const noexcept { return data_.type_index(); }

/*! \brief Returns true if the Expected contains a success value. */
TVM_FFI_INLINE bool is_ok() const noexcept {
return data_.type_index() != TypeIndex::kTVMFFIError;
Expand Down Expand Up @@ -186,9 +195,78 @@ class Expected {
}

private:
Expected() = default;

friend struct details::ExpectedUnsafe;

Any data_; // Invariant: holds a T (type_index != kTVMFFIError) or an Error.
};

namespace details {

/*!
* \brief Unsafe raw-storage helpers for Expected.
*
* These helpers bypass normal value checking and are intended for ABI boundaries
* that already know the underlying Any storage holds either a valid T or Error.
*/
struct ExpectedUnsafe {
/*!
* \brief Move a raw TVMFFIAny into Expected storage.
* \tparam T The Expected success type.
* \param raw The raw FFI value to move.
* \return Expected backed by moved Any storage.
*/
template <typename T>
TVM_FFI_INLINE static Expected<T> MoveFromTVMFFIAny(TVMFFIAny raw) {
Expected<T> result;
result.data_ = AnyUnsafe::MoveTVMFFIAnyToAny(&raw);
return result;
}

/*!
* \brief Move Expected storage to a raw TVMFFIAny.
* \tparam T The Expected success type.
* \param result The Expected value to move from.
* \return Raw FFI value containing moved underlying Any storage.
*/
template <typename T>
TVM_FFI_INLINE static TVMFFIAny MoveToTVMFFIAny(Expected<T>&& result) {
return AnyUnsafe::MoveAnyToTVMFFIAny(std::move(result.data_));
}

/*!
* \brief Return the underlying Any storage.
* \tparam T The Expected success type.
* \param result The Expected value to inspect.
* \return Const reference to the raw Any storage.
*/
template <typename T>
TVM_FFI_INLINE static const Any& GetData(const Expected<T>& result) noexcept {
return result.data_;
}

/*!
* \brief Read an Expected success value as a compatible raw storage type.
* \tparam T The type to read from the underlying Any storage.
* \tparam U The Expected success type.
* \param result The Expected value to read from.
* \return The stored value decoded as T.
*
* \note This assumes \p result stores T-compatible Any storage, or Error.
*/
template <typename T, typename U>
TVM_FFI_INLINE static T ValueAs(const Expected<U>& result) {
const Any& data = result.data_;
if (TVM_FFI_PREDICT_TRUE(data.type_index() != TypeIndex::kTVMFFIError)) {
return AnyUnsafe::CopyFromAnyViewAfterCheck<T>(data);
}
throw AnyUnsafe::CopyFromAnyViewAfterCheck<Error>(data);
}
};

} // namespace details

// TypeTraits specialization for Expected<T>
template <typename T>
inline constexpr bool use_default_type_traits_v<Expected<T>> = false;
Expand Down
Loading
Loading