tqchen commented on code in PR #649:
URL: https://github.com/apache/tvm-ffi/pull/649#discussion_r3618434981


##########
include/tvm/ffi/extra/structural_mutator.h:
##########
@@ -0,0 +1,1024 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*!
+ * \file tvm/ffi/extra/structural_mutator.h
+ * \brief Structural mutation and in-place mutation API.
+ */
+#ifndef TVM_FFI_EXTRA_STRUCTURAL_MUTATOR_H_
+#define TVM_FFI_EXTRA_STRUCTURAL_MUTATOR_H_
+
+#include <tvm/ffi/any.h>
+#include <tvm/ffi/c_api.h>
+#include <tvm/ffi/cast.h>
+#include <tvm/ffi/container/array.h>
+#include <tvm/ffi/container/tuple.h>
+#include <tvm/ffi/container/variant.h>
+#include <tvm/ffi/expected.h>
+#include <tvm/ffi/extra/visit_error_context.h>
+#include <tvm/ffi/function.h>
+#include <tvm/ffi/function_details.h>
+#include <tvm/ffi/optional.h>
+#include <tvm/ffi/reflection/accessor.h>
+
+#include <cstddef>
+#include <exception>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+namespace tvm {
+namespace ffi {
+
+class StructuralMutatorObj;
+
+/*!
+ * \brief ABI callback type for structural mutation with optional in-place 
dispatch.
+ *
+ * \param mutator The active structural mutator.
+ * \param value The borrowed value to transform.
+ * \param require_mutate Whether the non-in-place mutation path is mandatory.
+ */
+using FStructuralMaybeInplaceMutate = TVMFFIAny (*)(StructuralMutatorObj* 
mutator, AnyView value,
+                                                    bool require_mutate) 
noexcept;
+
+/*!
+ * \brief ABI callback type for structural mutation and in-place mutation 
dispatch.
+ *
+ * \param mutator The active structural mutator.
+ * \param value The borrowed value to transform.
+ * \return Raw ``TVMFFIAny`` containing the transformed value for mutation, 
FFI None for
+ *         successful in-place mutation, or an Error.
+ */
+using FStructuralTransform = TVMFFIAny (*)(StructuralMutatorObj* mutator, 
AnyView value) noexcept;
+
+namespace details {
+
+/*!
+ * \brief Move a structural transformation result to raw ABI storage and 
annotate failures.
+ *
+ * \tparam T The transformation success type.
+ * \param result The transformation result to move into raw ABI storage.
+ * \param error_context The borrowed input view held by the current dispatch 
frame and used for
+ *        error reporting after transformation.
+ * \return Raw ``TVMFFIAny`` storing the success value or Error.
+ */
+template <typename T>
+TVM_FFI_INLINE static TVMFFIAny MoveStructuralTransformResultToTVMFFIAny(
+    Expected<T> result, AnyView error_context) noexcept {
+  if (TVM_FFI_PREDICT_FALSE(result.is_err())) {
+    if (error_context.type_index() >= TypeIndex::kTVMFFIStaticObjectBegin) {
+      Error err = result.error();
+      UpdateVisitErrorContext(err, error_context.cast<ObjectRef>());
+    }
+  }
+  return ExpectedUnsafe::MoveToTVMFFIAny(std::move(result));
+}
+
+// Dispatch a type-specific structural mutation or in-place mutation hook.
+template <typename T>
+TVM_FFI_INLINE static Expected<T> 
DispatchTypeAttrHookExpected(StructuralMutatorObj* mutator,
+                                                               AnyView value, 
AnyView attr,
+                                                               
std::string_view attr_name) noexcept;
+
+// Copy and structurally mutate the reflected fields of an object-backed value.
+TVM_FFI_INLINE static Expected<Any> 
MutateReflectedFieldsExpected(StructuralMutatorObj* mutator,
+                                                                  AnyView 
value) noexcept;
+
+// Structurally transform the reflected fields of an object-backed value in 
place.
+TVM_FFI_INLINE static Expected<void> InplaceMutateReflectedFieldsExpected(
+    StructuralMutatorObj* mutator, AnyView value) noexcept;
+
+}  // namespace details
+
+/*!
+ * \brief VTable ABI for \ref StructuralMutator dispatch.
+ */
+struct StructuralMutatorVTable {
+  /*!
+   * \brief Select mutation or in-place mutation for a value.
+   *
+   * \param mutator The active structural mutator.
+   * \param value The borrowed value to transform by mutation or in-place 
mutation.
+   * \param require_mutate Whether the non-in-place mutation path is 
mandatory. False permits, but
+   *        does not require, in-place mutation.
+   * \return Raw ``TVMFFIAny`` carrying the transformed value or Error.
+   */
+  FStructuralMaybeInplaceMutate maybe_inplace_mutate = nullptr;
+  /*!
+   * \brief Mutate a value without intentionally modifying the source in place.
+   *
+   * \param mutator The active structural mutator.
+   * \param value The borrowed value to mutate.
+   * \return Raw ``TVMFFIAny`` carrying the mutated value or Error.
+   */
+  FStructuralTransform mutate = nullptr;
+  /*!
+   * \brief Transform a value using the explicit in-place mutation path.
+   *
+   * \param mutator The active structural mutator.
+   * \param value The borrowed value to transform in place.
+   * \return Raw ``TVMFFIAny`` carrying None on success or Error on failure.
+   */
+  FStructuralTransform inplace_mutate = nullptr;
+};
+
+/*!
+ * \brief Object node of a structural mutator.
+ */
+class StructuralMutatorObj : public Object {
+ public:
+  /*! \brief Construct the default structural mutator. */
+  StructuralMutatorObj() : StructuralMutatorObj(VTable()) {}
+
+  /*!
+   * \brief Mutate a value, using in-place mutation when permitted.
+   *
+   * \param value The borrowed value to transform.
+   * \param require_mutate Whether the non-in-place mutation path is 
mandatory. The default value
+   *        is false, which permits in-place mutation.
+   * \return The transformed owning value.
+   * \throws Error if transformation fails.
+   */
+  TVM_FFI_INLINE Any MaybeInplaceMutate(AnyView value, bool require_mutate = 
false) {
+    return MaybeInplaceMutateExpected(value, require_mutate).value();
+  }
+
+  /*!
+   * \brief Exception-free form of \ref MaybeInplaceMutate.
+   *
+   * \param value The borrowed value to transform.
+   * \param require_mutate Whether the non-in-place mutation path is 
mandatory. The default value
+   *        is false, which permits in-place mutation.
+   * \return The transformed owning value, or an Error if transformation 
failed.
+   */
+  TVM_FFI_INLINE Expected<Any> MaybeInplaceMutateExpected(AnyView value,
+                                                          bool require_mutate 
= false) noexcept {
+    return details::ExpectedUnsafe::MoveFromTVMFFIAny<Any>(
+        (*vtable_->maybe_inplace_mutate)(this, value, require_mutate));
+  }
+
+  /*!
+   * \brief Apply the default mutation or in-place mutation selection logic 
directly.
+   *
+   * \param value The value to transform by mutation or in-place mutation.
+   * \param require_mutate Whether the non-in-place mutation path is 
mandatory. Defaults to false.
+   * \return The transformed owning value.
+   * \throws Error if hook validation or transformation fails.
+   */
+  TVM_FFI_INLINE Any DefaultMaybeInplaceMutate(AnyView value, bool 
require_mutate = false) {
+    return DefaultMaybeInplaceMutateExpected(value, require_mutate).value();
+  }
+
+  /*!
+   * \brief Exception-free form of \ref DefaultMaybeInplaceMutate.
+   *
+   * \param value The value to transform by mutation or in-place mutation.
+   * \param require_mutate Whether the non-in-place mutation path is 
mandatory. Defaults to false.
+   * \return The transformed owning value, or an Error if selection or 
transformation failed.
+   */
+  TVM_FFI_INLINE Expected<Any> DefaultMaybeInplaceMutateExpected(
+      AnyView value, bool require_mutate = false) noexcept {
+    // Check that both mutate and inplace_mutate hooks are defined.
+    static reflection::TypeAttrColumn 
mutate_column(reflection::type_attr::kStructuralMutate);
+    static reflection::TypeAttrColumn inplace_mutate_column(
+        reflection::type_attr::kStructuralInplaceMutate);
+    int32_t type_index = value.type_index();
+    AnyView mutate_attr = mutate_column[type_index];
+    AnyView inplace_mutate_attr = inplace_mutate_column[type_index];
+    bool has_mutate = mutate_attr.type_index() != TypeIndex::kTVMFFINone;
+    bool has_inplace_mutate = inplace_mutate_attr.type_index() != 
TypeIndex::kTVMFFINone;
+    if (has_mutate != has_inplace_mutate) {
+      return Unexpected(Error("TypeError",
+                              "One of " + 
std::string(reflection::type_attr::kStructuralMutate) +
+                                  " and " +
+                                  
std::string(reflection::type_attr::kStructuralInplaceMutate) +
+                                  " is undefined, should provide both of 
them.",
+                              ""));
+    }
+    if (!require_mutate) {
+      Expected<void> result = InplaceMutateExpected(value);
+      if (TVM_FFI_PREDICT_FALSE(result.is_err())) {
+        return Unexpected(std::move(result).error());
+      }
+      return Any(value);
+    }
+    return MutateExpected(value);
+  }
+
+  /*!
+   * \brief Mutate a value through the mutator vtable with copy-on-write 
behavior.
+   *
+   * \param value The value to mutate.
+   * \return The mutated value with copy-on-write behavior.
+   * \throws Error if mutation fails.
+   */
+  TVM_FFI_INLINE Any Mutate(AnyView value) { return 
MutateExpected(value).value(); }
+
+  /*!
+   * \brief Exception-free form of \ref Mutate.
+   *
+   * \param value The value to mutate.
+   * \return The mutated value with copy-on-write behavior, or an Error if 
mutation failed.
+   */
+  TVM_FFI_INLINE Expected<Any> MutateExpected(AnyView value) noexcept {
+    return 
details::ExpectedUnsafe::MoveFromTVMFFIAny<Any>((*vtable_->mutate)(this, 
value));
+  }
+
+  /*!
+   * \brief Apply the default structural mutation with copy-on-write behavior.
+   *
+   * \param value The value to mutate.
+   * \return The mutated value with copy-on-write behavior.
+   * \throws Error if hook dispatch, copying, or field mutation fails.
+   */
+  TVM_FFI_INLINE Any DefaultMutate(AnyView value) { return 
DefaultMutateExpected(value).value(); }
+
+  /*!
+   * \brief Exception-free form of \ref DefaultMutate.
+   *
+   * \param value The value to mutate.
+   * \return The mutated value, or an Error if hook dispatch, copying, or 
field mutation failed.
+   */
+  TVM_FFI_INLINE Expected<Any> DefaultMutateExpected(AnyView value) noexcept {
+    int32_t type_index = value.type_index();
+    static reflection::TypeAttrColumn 
column(reflection::type_attr::kStructuralMutate);
+    AnyView attr = column[type_index];
+    if (attr.type_index() != TypeIndex::kTVMFFINone) {
+      return details::DispatchTypeAttrHookExpected<Any>(this, value, attr,
+                                                        
reflection::type_attr::kStructuralMutate);
+    }
+    if (type_index < TypeIndex::kTVMFFIStaticObjectBegin) {
+      return Any(value);
+    }
+    return details::MutateReflectedFieldsExpected(this, value);
+  }
+
+  /*!
+   * \brief Transform a value through the explicit in-place mutation vtable 
entry.
+   *
+   * \param value The value to transform in place.
+   * \return Nothing. The input value is mutated directly.
+   * \throws Error if transformation fails.
+   */
+  TVM_FFI_INLINE void InplaceMutate(AnyView value) { 
InplaceMutateExpected(value).value(); }
+
+  /*!
+   * \brief Exception-free form of \ref InplaceMutate.
+   *
+   * \param value The value to transform in place.
+   * \return Successful completion, or an Error if transformation failed. 
Mutations completed
+   *         before the Error are not rolled back.
+   */
+  TVM_FFI_INLINE Expected<void> InplaceMutateExpected(AnyView value) noexcept {
+    return details::ExpectedUnsafe::MoveFromTVMFFIAny<void>(
+        (*vtable_->inplace_mutate)(this, value));
+  }
+
+  /*!
+   * \brief Apply the default structural in-place mutation.
+   *
+   * \param value The value to transform in place.
+   * \return Nothing. The input value is mutated directly.
+   * \throws Error if hook dispatch or reflected mutation fails.
+   */
+  TVM_FFI_INLINE void DefaultInplaceMutate(AnyView value) {
+    DefaultInplaceMutateExpected(value).value();
+  }
+
+  /*!
+   * \brief Exception-free form of \ref DefaultInplaceMutate.
+   *
+   * \param value The value to transform in place.
+   * \return Successful completion, or an Error if hook dispatch or reflected 
mutation failed.
+   *         Mutations completed before the Error are not rolled back.
+   */
+  TVM_FFI_INLINE Expected<void> DefaultInplaceMutateExpected(AnyView value) 
noexcept {
+    int32_t type_index = value.type_index();
+    static reflection::TypeAttrColumn 
column(reflection::type_attr::kStructuralInplaceMutate);
+    AnyView attr = column[type_index];
+    if (attr.type_index() != TypeIndex::kTVMFFINone) {
+      return details::DispatchTypeAttrHookExpected<void>(
+          this, value, attr, reflection::type_attr::kStructuralInplaceMutate);
+    }
+    if (type_index < TypeIndex::kTVMFFIStaticObjectBegin) {
+      return Expected<void>();
+    }
+    return details::InplaceMutateReflectedFieldsExpected(this, value);
+  }
+
+  /*!
+   * \brief Return the current def-region context.
+   * \return The active def-region kind.
+   */
+  TVM_FFI_INLINE TVMFFIDefRegionKind def_region_kind() const { return 
def_region_mode_; }
+
+  /*!
+   * \brief Temporarily switch the def-region context while invoking \p 
callback.
+   *
+   * \param kind The def-region kind to set during the callback.
+   * \param callback A nullary callable that performs recursive transformation.
+   * \return The value returned by \p callback.
+   */
+  template <typename Callback>
+  TVM_FFI_INLINE auto WithDefRegionKind(TVMFFIDefRegionKind kind, Callback&& 
callback) {
+    class Scope {
+     public:
+      Scope(StructuralMutatorObj* mutator, TVMFFIDefRegionKind kind)
+          : mutator_(mutator), old_kind_(mutator->def_region_mode_) {
+        mutator_->def_region_mode_ = kind;
+      }
+      ~Scope() { mutator_->def_region_mode_ = old_kind_; }
+      Scope(const Scope&) = delete;
+      Scope& operator=(const Scope&) = delete;
+
+     private:
+      StructuralMutatorObj* mutator_;
+      TVMFFIDefRegionKind old_kind_;
+    };
+    Scope scope(this, kind);
+    return std::forward<Callback>(callback)();
+  }
+
+  /// \cond Doxygen_Suppress
+  static constexpr const bool _type_mutable = true;
+  TVM_FFI_DECLARE_OBJECT_INFO("ffi.StructuralMutator", StructuralMutatorObj, 
Object);
+  /// \endcond
+
+ protected:
+  /*!
+   * \brief Construct a structural mutator subclass with a custom dispatch 
vtable.
+   *
+   * \param vtable The non-null dispatch table for this mutator.
+   */
+  explicit StructuralMutatorObj(const StructuralMutatorVTable* vtable) : 
vtable_(vtable) {}
+
+  /*!
+   * \brief Required ABI dispatch table.
+   */
+  const StructuralMutatorVTable* vtable_ = nullptr;
+
+  /*!
+   * \brief Current def-region context for def-region-aware structural 
transformation.
+   */
+  TVMFFIDefRegionKind def_region_mode_ = kTVMFFIDefRegionKindNone;
+
+ private:
+  /*!
+   * \brief Return the vtable used by the default structural mutator.
+   * \return Pointer to the static default vtable.
+   */
+  static const StructuralMutatorVTable* VTable() {
+    static const StructuralMutatorVTable vtable{
+        &StructuralMutatorObj::DispatchMaybeInplaceMutate,
+        &StructuralMutatorObj::DispatchMutate,
+        &StructuralMutatorObj::DispatchInplaceMutate,
+    };
+    return &vtable;
+  }
+
+  /*!
+   * \brief Dispatch the default transformation from the ABI vtable.
+   *
+   * \param mutator The active structural mutator.
+   * \param value The borrowed value to transform.
+   * \param require_mutate Whether the non-in-place mutation path is mandatory 
for this call.
+   * \return Raw ``TVMFFIAny`` storing the transformed value or Error.
+   *
+   * \note Validation errors raised before a branch is selected are returned 
without adding a
+   *       visit-context frame at this forwarding layer to avoid duplicated 
error context.
+   */
+  static TVMFFIAny DispatchMaybeInplaceMutate(StructuralMutatorObj* mutator, 
AnyView value,
+                                              bool require_mutate) noexcept {
+    auto result = mutator->DefaultMaybeInplaceMutateExpected(value, 
require_mutate);
+    return details::ExpectedUnsafe::MoveToTVMFFIAny(std::move(result));
+  }
+
+  /*!
+   * \brief Dispatch default mutation from the ABI vtable.
+   *
+   * \param mutator The active structural mutator.
+   * \param value The borrowed value to mutate.
+   * \return Raw ``TVMFFIAny`` storing the mutated value or Error.
+   */
+  static TVMFFIAny DispatchMutate(StructuralMutatorObj* mutator, AnyView 
value) noexcept {
+    auto result = mutator->DefaultMutateExpected(value);
+    return 
details::MoveStructuralTransformResultToTVMFFIAny(std::move(result), value);
+  }
+
+  /*!
+   * \brief Dispatch default in-place mutation from the ABI vtable.
+   *
+   * \param mutator The active structural mutator.
+   * \param value The borrowed value to transform in place.
+   * \return Raw ``TVMFFIAny`` storing None on success or Error on failure.
+   */
+  static TVMFFIAny DispatchInplaceMutate(StructuralMutatorObj* mutator, 
AnyView value) noexcept {
+    auto result = mutator->DefaultInplaceMutateExpected(value);
+    return 
details::MoveStructuralTransformResultToTVMFFIAny(std::move(result), value);
+  }
+};
+
+/*!
+ * \brief ObjectRef wrapper for \ref StructuralMutatorObj.
+ *
+ * \sa StructuralMutatorObj
+ */
+class StructuralMutator : public ObjectRef {
+ public:
+  /*! \brief Construct the default structural mutator. */
+  StructuralMutator() : ObjectRef(make_object<StructuralMutatorObj>()) {}
+
+  /*!
+   * \brief Construct from an existing mutator object pointer.
+   * \param n The object pointer to wrap.
+   */
+  explicit StructuralMutator(ObjectPtr<StructuralMutatorObj> n) : 
ObjectRef(std::move(n)) {}
+
+  /// \cond Doxygen_Suppress
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(StructuralMutator, ObjectRef, 
StructuralMutatorObj);
+  /// \endcond
+};
+
+namespace details {
+
+/*!
+ * \brief Dispatch a type-specific structural transformation hook.
+ *
+ * \tparam T The hook's success type: ``Any`` for mutation or ``void`` for 
in-place mutation.
+ * \param mutator The active structural mutator.
+ * \param value The borrowed value passed to the hook.
+ * \param attr The registered type attribute value.
+ * \param attr_name The attribute name used in type errors.
+ * \return The hook result, or an Error if the hook fails or \p attr has an 
invalid type.
+ */
+template <typename T>
+TVM_FFI_INLINE static Expected<T> DispatchTypeAttrHookExpected(
+    StructuralMutatorObj* mutator, AnyView value, AnyView attr,
+    std::string_view attr_name) noexcept {
+  // case 1: Type-specific override registered as an opaque ABI function 
pointer.
+  if (attr.type_index() == TypeIndex::kTVMFFIOpaquePtr) {
+    auto* hook = reinterpret_cast<FStructuralTransform>(attr.cast<void*>());
+    return details::ExpectedUnsafe::MoveFromTVMFFIAny<T>((*hook)(mutator, 
value));
+  }
+
+  // case 2: Type-specific override registered as an ffi::Function.
+  if (attr.type_index() == TypeIndex::kTVMFFIFunction) {
+    return attr.cast<Function>().CallExpected<T>(mutator, value);
+  }
+
+  return Unexpected(
+      Error("TypeError",
+            std::string(attr_name) + " must be an opaque function pointer or 
ffi.Function", ""));
+}
+
+/*!
+ * \brief Transform every reflected structural field of an object.
+ *
+ * \tparam T The transformation success type: ``Any`` for mutation or ``void`` 
for in-place
+ *         mutation.
+ * \tparam Callback A callable compatible with
+ *         ``Expected<Any>(AnyView, TVMFFIDefRegionKind)``.
+ * \param value The original object-backed value.
+ * \param result The owning shallow-copy result in copy-on-write mode, or a 
successful
+ *        ``Expected<void>`` in in-place mode. It is also used to propagate 
the first Error.
+ * \param copy_on_write Whether to transform a distinct shallow copy instead 
of \p value.
+ * \param callback The recursive field transformation callback.
+ * \return For mutation, the original value when no field changes or the 
transformed copy
+ *         otherwise; for in-place mutation, successful completion. Returns an 
Error on failure.
+ */
+template <typename T, typename Callback>
+TVM_FFI_INLINE static Expected<T> TransformReflectedFieldsExpected(AnyView 
value,
+                                                                   Expected<T> 
result,
+                                                                   bool 
copy_on_write,
+                                                                   Callback 
callback) noexcept {
+  const Object* obj = value.as<Object>();
+  Object* new_obj = const_cast<Object*>(obj);
+  if (copy_on_write) {
+    const Any& result_value = details::ExpectedUnsafe::GetData(result);
+    new_obj = const_cast<Object*>(result_value.as<Object>());
+    // Copy-on-write mutation requires a distinct target so partial updates 
cannot modify the
+    // source.
+    if (TVM_FFI_PREDICT_FALSE(new_obj == nullptr || result.type_index() != 
value.type_index() ||
+                              new_obj == obj)) {
+      return Unexpected(
+          Error("TypeError",
+                "Shallow copy callback must return a distinct object with the 
same type as its "
+                "input",
+                ""));
+    }
+  }
+  const TVMFFITypeInfo* type_info = TVMFFIGetTypeInfo(new_obj->type_index());
+
+  bool field_changed = false;
+  reflection::ForEachFieldInfoWithEarlyStop(
+      type_info, [&](const TVMFFIFieldInfo* field_info) -> bool {
+        if (field_info->flags & kTVMFFIFieldFlagBitMaskSEqHashIgnore) {
+          return false;
+        }
+
+        Any field_value;
+        const void* field_addr = reinterpret_cast<const char*>(new_obj) + 
field_info->offset;
+        int ret_code = field_info->getter(const_cast<void*>(field_addr),
+                                          
reinterpret_cast<TVMFFIAny*>(&field_value));
+        if (TVM_FFI_PREDICT_FALSE(ret_code != 0)) {
+          result = Unexpected(details::MoveFromSafeCallRaised());
+          return true;
+        }
+
+        TVMFFIDefRegionKind kind = kTVMFFIDefRegionKindNone;
+        if (field_info->flags & kTVMFFIFieldFlagBitMaskSEqHashDefNonRecursive) 
{
+          kind = kTVMFFIDefRegionKindNonRecursive;
+        } else if (field_info->flags & 
kTVMFFIFieldFlagBitMaskSEqHashDefRecursive) {
+          kind = kTVMFFIDefRegionKindRecursive;
+        }
+
+        Expected<Any> transformed_field = callback(field_value, kind);
+        if (TVM_FFI_PREDICT_FALSE(transformed_field.is_err())) {
+          result = Unexpected(std::move(transformed_field).error());
+          return true;
+        }
+        const Any& new_field = 
details::ExpectedUnsafe::GetData(transformed_field);
+        if (field_value.same_as(new_field)) {
+          return false;
+        }
+
+        if (TVM_FFI_PREDICT_FALSE(field_info->setter == nullptr)) {
+          result = Unexpected(
+              Error("TypeError",
+                    "Cannot structurally mutate field `" +
+                        std::string(field_info->name.data, 
field_info->name.size) + "` of type `" +
+                        std::string(type_info->type_key.data, 
type_info->type_key.size) +
+                        "` because it does not define a setter",
+                    ""));
+          return true;
+        }
+
+        void* new_field_addr = reinterpret_cast<char*>(new_obj) + 
field_info->offset;
+        ret_code = reflection::CallFieldSetter(field_info, new_field_addr,
+                                               reinterpret_cast<const 
TVMFFIAny*>(&new_field));
+        if (TVM_FFI_PREDICT_FALSE(ret_code != 0)) {
+          result = Unexpected(details::MoveFromSafeCallRaised());
+          return true;
+        }
+        field_changed = true;
+        return false;
+      });
+
+  if (TVM_FFI_PREDICT_FALSE(result.is_err())) {
+    return result;
+  }
+  if constexpr (!std::is_void_v<T>) {
+    if (copy_on_write && !field_changed) {
+      return Any(value);
+    }
+  }
+  return result;
+}
+
+/*!
+ * \brief Mutate the reflected structural fields of an object-backed value.
+ *
+ * \param mutator The active structural mutator.
+ * \param value The object-backed value to mutate.
+ * \return The original value when no field changes, a transformed shallow 
copy otherwise, or an
+ *         Error if copying or mutation failed.
+ */
+TVM_FFI_INLINE static Expected<Any> 
MutateReflectedFieldsExpected(StructuralMutatorObj* mutator,
+                                                                  AnyView 
value) noexcept {
+  const Object* obj = value.as<Object>();
+  int32_t type_index = obj->type_index();
+
+  static reflection::TypeAttrColumn 
column(reflection::type_attr::kShallowCopy);
+  AnyView attr = column[type_index];
+  if (TVM_FFI_PREDICT_FALSE(attr.type_index() != TypeIndex::kTVMFFIFunction)) {
+    return Unexpected(
+        Error("TypeError",
+              std::string(reflection::type_attr::kShallowCopy) + " must be an 
ffi.Function", ""));
+  }
+
+  Expected<Any> result = attr.cast<Function>().CallExpected<Any>(value);
+  if (TVM_FFI_PREDICT_FALSE(result.is_err())) {
+    return result;
+  }
+
+  return TransformReflectedFieldsExpected(
+      value, std::move(result), true,
+      [mutator](AnyView field_value, TVMFFIDefRegionKind kind) noexcept -> 
Expected<Any> {
+        if (kind != kTVMFFIDefRegionKindNone) {
+          return mutator->WithDefRegionKind(kind,
+                                            [&]() { return 
mutator->MutateExpected(field_value); });
+        }
+        return mutator->MutateExpected(field_value);
+      });
+}
+
+/*!
+ * \brief Transform the reflected structural fields of an object-backed value 
in place.
+ *
+ * \param mutator The active structural mutator.
+ * \param value The object-backed value whose fields should be transformed in 
place.
+ * \return Successful completion or an Error. Mutations made before an Error 
are not rolled back.
+ */
+TVM_FFI_INLINE static Expected<void> InplaceMutateReflectedFieldsExpected(
+    StructuralMutatorObj* mutator, AnyView value) noexcept {
+  return TransformReflectedFieldsExpected(
+      value, Expected<void>(), false,
+      [mutator](AnyView field_value, TVMFFIDefRegionKind kind) noexcept -> 
Expected<Any> {
+        const Object* field_obj = field_value.as<Object>();
+        // The reflection getter adds the second reference to a logically 
unique object field.
+        bool require_mutate = field_obj != nullptr && field_obj->use_count() > 
2;
+        if (kind != kTVMFFIDefRegionKindNone) {
+          return mutator->WithDefRegionKind(kind, [&]() {
+            return mutator->MaybeInplaceMutateExpected(field_value, 
require_mutate);
+          });
+        }
+        return mutator->MaybeInplaceMutateExpected(field_value, 
require_mutate);
+      });
+}
+
+}  // namespace details
+
+// ---------------------------------------------------------------------------
+// Structural Map API.
+// ---------------------------------------------------------------------------
+
+/*!
+ * \brief Callback order for \ref tvm::ffi::StructuralMap.
+ */
+enum class MapOrder : int32_t {
+  /*! \brief Invoke the callback first, then recursively map the value it 
returns. */
+  kPreOrder = 0,
+  /*! \brief Map children first, then invoke the callback on the mapped value. 
*/

Review Comment:
   maybe reuse the walkorder?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to