Skip to main content

tvm_ffi/extra/
structural_mutate.rs

1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements.  See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership.  The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License.  You may obtain a copy of the License at
9 *
10 *   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied.  See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20//! Native Rust structural mutation and mapping.
21//!
22//! [`structural_mutate`] lets a mutator drive recursion, while
23//! [`structural_map`] applies callbacks around engine-owned recursion.
24
25use std::cell::{Cell, RefCell};
26use std::collections::HashMap;
27use std::ffi::c_void;
28use std::marker::PhantomData;
29use std::ops::{ControlFlow, Deref};
30use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
31use std::ptr::NonNull;
32use std::rc::Rc;
33use std::sync::atomic::{AtomicUsize, Ordering};
34use std::sync::LazyLock;
35
36use crate::any::{Any, AnyView};
37use crate::error::{Error, Result, RUNTIME_ERROR, TYPE_ERROR};
38use crate::function::Function;
39use crate::object::{self, Object, ObjectArc, ObjectCore};
40use crate::reflection::TypeAttrColumn;
41use crate::tvm_ffi_sys::TVMFFIFieldFlagBitMask::{
42    kTVMFFIFieldFlagBitMaskSEqHashIgnore, kTVMFFIFieldFlagBitSetterIsFunctionObj,
43};
44use crate::tvm_ffi_sys::{
45    TVMFFIAny, TVMFFIAnyViewToOwnedAny, TVMFFIByteArray, TVMFFIFieldInfo, TVMFFIFieldSetter,
46    TVMFFIFunctionCall, TVMFFIGetTypeInfo, TVMFFIObject, TVMFFITypeAttrColumn, TVMFFITypeIndex,
47    TVMFFITypeKeyToIndex,
48};
49use crate::tvm_ffi_sys::{TVMFFIObjectHandle, TVMFFISEqHashKind};
50
51use super::structural_common::{
52    impl_callback_chain_tuple_arities, is_plain_inline, same_shallow,
53    try_to_owned_without_normalization, with_structural_error_context,
54};
55use super::structural_visit::{
56    field_def_region, for_each_field_info, free_var_child_region, type_attr_column, type_key_of,
57    DefRegionKind, WalkOrder,
58};
59use super::unchanged::is_unchanged;
60pub use super::unchanged::{Unchanged, UnchangedOr};
61
62const STRUCTURAL_MUTATE_ATTR: &str = "__s_mutate__";
63const STRUCTURAL_MAYBE_INPLACE_MUTATE_ATTR: &str = "__s_maybe_inplace_mutate__";
64const SHALLOW_COPY_ATTR: &str = "__ffi_shallow_copy__";
65const FLAG_SEQ_HASH_IGNORE: i64 = kTVMFFIFieldFlagBitMaskSEqHashIgnore as i64;
66const FLAG_SETTER_IS_FUNCTION: i64 = kTVMFFIFieldFlagBitSetterIsFunctionObj as i64;
67
68/// Borrowed value passed to structural map and mutation callbacks.
69pub use super::structural_common::StructuralValue as MapValue;
70
71/// Result type produced by a structural-map callback.
72#[doc(hidden)]
73pub type MapResult = Result<Any>;
74
75mod callback_result_sealed {
76    use super::{Any, Result};
77
78    pub trait Sealed {}
79
80    impl<T: Into<Any>> Sealed for T {}
81    impl<T: Into<Any>> Sealed for Result<T> {}
82}
83
84/// Convert an infallible or fallible callback result into [`MapResult`].
85///
86/// A callback may return any value convertible into [`Any`], or wrap it in
87/// [`Result`] to use `?`.
88///
89/// This trait is sealed and is not an extension point.
90#[doc(hidden)]
91pub trait IntoMapResult: callback_result_sealed::Sealed {
92    fn into_map_result(self) -> MapResult;
93}
94
95impl<T: Into<Any>> IntoMapResult for T {
96    #[inline]
97    fn into_map_result(self) -> MapResult {
98        Ok(self.into())
99    }
100}
101
102impl<T: Into<Any>> IntoMapResult for Result<T> {
103    #[inline]
104    fn into_map_result(self) -> MapResult {
105        self.map(Into::into)
106    }
107}
108
109/// State and recursive operations available to a callback-chain mutation.
110///
111/// A matched callback owns mutation of its value. Recursive operations
112/// reborrow the mutator, so mutable state cannot remain borrowed across them.
113pub struct MutateContext<'a, State, Driver: ?Sized = dyn MutateContextDriver<State> + 'a> {
114    driver: &'a mut Driver,
115    current: MapValue,
116    def_region_kind: DefRegionKind,
117    _state: PhantomData<fn() -> State>,
118    _not_send_sync: PhantomData<Rc<()>>,
119}
120
121/// Recursive mutation operations passed to closure callback chains.
122///
123/// Typed `#[dispatch(mutate)]` implementations use [`Mutator`] instead and
124/// keep their mutable pass state directly on the dispatch object.
125pub type CallbackMutator<'a, State = (), Driver = dyn MutateContextDriver<State> + 'a> =
126    MutateContext<'a, State, Driver>;
127
128/// Recursion control passed to a typed `#[dispatch(mutate)]` handler.
129///
130/// The dispatch object owns all pass state. Recursive operations take that
131/// object explicitly so Rust can safely reborrow the same `&mut self` for the
132/// child call.
133pub struct Mutator {
134    current: MapValue,
135    def_region_kind: DefRegionKind,
136    _not_send_sync: PhantomData<Rc<()>>,
137}
138
139impl Mutator {
140    /// Complete borrowed value active at this callback.
141    #[inline(always)]
142    pub fn current(&self) -> &MapValue {
143        &self.current
144    }
145
146    /// Definition-region state active at the callback's current value.
147    #[inline(always)]
148    pub fn def_region_kind(&self) -> DefRegionKind {
149        self.def_region_kind
150    }
151
152    /// Definition region active at the callback's current value.
153    #[inline(always)]
154    pub fn region(&self) -> DefRegionKind {
155        self.def_region_kind
156    }
157
158    /// Mutate a borrowed child through the same typed dispatch object.
159    #[inline(always)]
160    pub fn mutate<D, T>(&mut self, dispatch: &mut D, value: &T) -> Result<Any>
161    where
162        D: MutateDispatch,
163        for<'x> AnyView<'x>: From<&'x T>,
164    {
165        StructuralMutator::mutate(dispatch, value, self.def_region_kind)
166    }
167
168    /// Mutate a borrowed child under an explicit definition-region state.
169    #[inline(always)]
170    pub fn mutate_with<D, T>(
171        &mut self,
172        dispatch: &mut D,
173        value: &T,
174        def_region_kind: DefRegionKind,
175    ) -> Result<Any>
176    where
177        D: MutateDispatch,
178        for<'x> AnyView<'x>: From<&'x T>,
179    {
180        StructuralMutator::mutate(dispatch, value, def_region_kind)
181    }
182
183    /// Mutate an owned child and permit reuse when it remains uniquely owned.
184    #[inline(always)]
185    pub fn maybe_inplace_mutate<D, T>(&mut self, dispatch: &mut D, value: T) -> Result<Any>
186    where
187        D: MutateDispatch,
188        T: Into<Any>,
189    {
190        self.maybe_inplace_mutate_with(dispatch, value, self.def_region_kind)
191    }
192
193    /// Mutate an owned child under an explicit definition-region state.
194    #[inline(always)]
195    pub fn maybe_inplace_mutate_with<D, T>(
196        &mut self,
197        dispatch: &mut D,
198        value: T,
199        def_region_kind: DefRegionKind,
200    ) -> Result<Any>
201    where
202        D: MutateDispatch,
203        T: Into<Any>,
204    {
205        StructuralMutator::maybe_inplace_mutate(dispatch, value, def_region_kind)
206    }
207
208    /// Apply default mutation to the callback's current value.
209    #[inline(always)]
210    pub fn default_mutate<D: MutateDispatch>(&mut self, dispatch: &mut D) -> Result<Any> {
211        StructuralMutator::default_mutate(dispatch, &self.current, self.def_region_kind)
212    }
213
214    /// Mutate a borrowed child while preserving an unchanged result.
215    #[inline]
216    pub fn mutate_result<D, T>(&mut self, dispatch: &mut D, value: &T) -> Result<UnchangedOr<Any>>
217    where
218        D: MutateDispatch,
219        for<'x> AnyView<'x>: From<&'x T>,
220    {
221        self.mutate_with_result(dispatch, value, self.def_region_kind)
222    }
223
224    /// Mutate a borrowed child under an explicit region, preserving unchanged.
225    #[inline]
226    pub fn mutate_with_result<D, T>(
227        &mut self,
228        dispatch: &mut D,
229        value: &T,
230        kind: DefRegionKind,
231    ) -> Result<UnchangedOr<Any>>
232    where
233        D: MutateDispatch,
234        for<'x> AnyView<'x>: From<&'x T>,
235    {
236        StructuralMutator::mutate_result(dispatch, value, kind)
237    }
238
239    /// Apply default mutation without materializing an unchanged original.
240    #[inline]
241    pub fn default_mutate_result<D: MutateDispatch>(
242        &mut self,
243        dispatch: &mut D,
244    ) -> Result<UnchangedOr<Any>> {
245        StructuralMutator::default_mutate_result(dispatch, &self.current, self.def_region_kind)
246    }
247
248    /// Look up an invocation-local identity substitution.
249    #[inline(always)]
250    pub fn var_remap_get<D: MutateDispatch>(
251        &mut self,
252        dispatch: &mut D,
253        var: &MapValue,
254    ) -> Result<Option<Any>> {
255        StructuralMutator::var_remap_get(dispatch, var)
256    }
257
258    /// Store an invocation-local identity substitution.
259    #[inline(always)]
260    pub fn var_remap_set<D: MutateDispatch>(
261        &mut self,
262        dispatch: &mut D,
263        var: &MapValue,
264        mutated_value: &Any,
265    ) -> Result<()> {
266        StructuralMutator::var_remap_set(dispatch, var, mutated_value)
267    }
268}
269
270#[doc(hidden)]
271/// Internal operations used by [`MutateContext`].
272///
273/// The dispatch macro keeps the concrete implementor visible to the compiler
274/// so recursive `mutate` calls can be inlined. This is not a user extension
275/// point.
276pub trait MutateContextDriver<State> {
277    fn state(&self) -> &State;
278    fn state_mut(&mut self) -> &mut State;
279    fn mutate_raw(
280        &mut self,
281        raw: TVMFFIAny,
282        def_region_kind: DefRegionKind,
283        permit: Permit,
284    ) -> Result<Any>;
285    fn default_mutate_raw(&mut self, raw: TVMFFIAny, def_region_kind: DefRegionKind)
286        -> Result<Any>;
287    fn var_remap_get_raw(&mut self, raw: TVMFFIAny) -> Result<Option<Any>>;
288    fn var_remap_set_raw(&mut self, raw: TVMFFIAny, mutated_value: &Any) -> Result<()>;
289}
290
291impl<State, Driver> MutateContext<'_, State, Driver>
292where
293    Driver: MutateContextDriver<State> + ?Sized,
294{
295    /// User state shared by every callback in this mutation.
296    #[inline(always)]
297    pub fn state(&self) -> &State {
298        self.driver.state()
299    }
300
301    /// Mutably borrow the user state.
302    #[inline(always)]
303    pub fn state_mut(&mut self) -> &mut State {
304        self.driver.state_mut()
305    }
306
307    /// Complete borrowed value active at this callback.
308    #[inline(always)]
309    pub fn current(&self) -> &MapValue {
310        &self.current
311    }
312
313    /// Definition-region state active at the callback's current value.
314    #[inline(always)]
315    pub fn def_region_kind(&self) -> DefRegionKind {
316        self.def_region_kind
317    }
318
319    /// Definition region active at the callback's current value.
320    #[inline]
321    pub fn region(&self) -> DefRegionKind {
322        self.def_region_kind
323    }
324
325    /// Mutate a borrowed value through the same callback chain. The value and
326    /// its descendants begin on the non-in-place path.
327    #[inline(always)]
328    pub fn mutate<T>(&mut self, value: &T) -> Result<Any>
329    where
330        for<'x> AnyView<'x>: From<&'x T>,
331    {
332        self.mutate_with(value, self.def_region_kind)
333    }
334
335    /// Mutate a borrowed value under an explicit definition-region state.
336    #[inline(always)]
337    pub fn mutate_with<T>(&mut self, value: &T, def_region_kind: DefRegionKind) -> Result<Any>
338    where
339        for<'x> AnyView<'x>: From<&'x T>,
340    {
341        let view = AnyView::from(value);
342        self.driver
343            .mutate_raw(*view.as_raw_ffi_any(), def_region_kind, Permit::Copy)
344            .and_then(|result| resolve_result(result, *view.as_raw_ffi_any()))
345    }
346
347    /// Mutate an owned value, allowing an in-place attempt when it remains
348    /// uniquely owned and no matched callback borrows it.
349    #[inline(always)]
350    pub fn maybe_inplace_mutate<T: Into<Any>>(&mut self, value: T) -> Result<Any> {
351        self.maybe_inplace_mutate_with(value, self.def_region_kind)
352    }
353
354    /// Mutate an owned value under an explicit definition-region state.
355    #[inline(always)]
356    pub fn maybe_inplace_mutate_with<T: Into<Any>>(
357        &mut self,
358        value: T,
359        def_region_kind: DefRegionKind,
360    ) -> Result<Any> {
361        let value = value.into();
362        let result = self.driver.mutate_raw(
363            *value.as_raw_ffi_any(),
364            def_region_kind,
365            Permit::MaybeInPlace,
366        )?;
367        Ok(if is_unchanged(&result) { value } else { result })
368    }
369
370    /// Apply default mutation to the callback's current value.
371    ///
372    /// This operation always uses the copy path because a callback may still
373    /// hold a shared borrow of the current value. It may be called repeatedly.
374    #[inline(always)]
375    pub fn default_mutate(&mut self) -> Result<Any> {
376        self.driver
377            .default_mutate_raw(self.current.raw(), self.def_region_kind)
378            .and_then(|result| resolve_result(result, self.current.raw()))
379    }
380
381    /// Mutate a borrowed child while preserving an unchanged result.
382    #[inline]
383    pub fn mutate_result<T>(&mut self, value: &T) -> Result<UnchangedOr<Any>>
384    where
385        for<'x> AnyView<'x>: From<&'x T>,
386    {
387        self.mutate_with_result(value, self.def_region_kind)
388    }
389
390    /// Mutate a borrowed child under an explicit region, preserving unchanged.
391    #[inline]
392    pub fn mutate_with_result<T>(
393        &mut self,
394        value: &T,
395        kind: DefRegionKind,
396    ) -> Result<UnchangedOr<Any>>
397    where
398        for<'x> AnyView<'x>: From<&'x T>,
399    {
400        let view = AnyView::from(value);
401        self.driver
402            .mutate_raw(*view.as_raw_ffi_any(), kind, Permit::Copy)
403            .and_then(UnchangedOr::from_carrier)
404    }
405
406    /// Apply default mutation without materializing an unchanged original.
407    #[inline]
408    pub fn default_mutate_result(&mut self) -> Result<UnchangedOr<Any>> {
409        self.driver
410            .default_mutate_raw(self.current.raw(), self.def_region_kind)
411            .and_then(UnchangedOr::from_carrier)
412    }
413
414    /// Look up an invocation-local identity substitution.
415    #[inline(always)]
416    pub fn var_remap_get(&mut self, var: &MapValue) -> Result<Option<Any>> {
417        self.driver.var_remap_get_raw(var.raw())
418    }
419
420    /// Store an invocation-local identity substitution.
421    #[inline(always)]
422    pub fn var_remap_set(&mut self, var: &MapValue, mutated_value: &Any) -> Result<()> {
423        self.driver.var_remap_set_raw(var.raw(), mutated_value)
424    }
425}
426
427/// Conversion into the mutator argument accepted by [`structural_mutate`].
428///
429/// Accepts a mutable low-level [`StructuralMutator`], a generated
430/// [`MutateDispatch`], or a first-match callback chain. Generated dispatch
431/// objects keep mutable pass state directly on themselves; [`MutateCallbacks`]
432/// remains available for closure callback chains with separate state.
433#[diagnostic::on_unimplemented(
434    message = "`{Self}` is not a supported `structural_mutate` mutator",
435    note = "accepted mutators: `&mut U` where `U: StructuralMutator`; a generated `MutateDispatch`; an `Fn` callback over an FFI value type `T`, `&N` of an object node type, or `&MapValue`, followed by `&mut CallbackMutator<State>`; or a tuple of up to 12 such callbacks (tuples may nest)",
436    note = "callback arguments need explicit type annotations; use `MutateCallbacks::new(state, callbacks)` for ordinary mutable callback state"
437)]
438pub trait IntoMutator<Marker> {
439    #[doc(hidden)]
440    fn mutate_root(self, root: Any) -> Result<Any>;
441}
442
443impl<U: StructuralMutator> IntoMutator<U> for &mut U {
444    fn mutate_root(self, root: Any) -> Result<Any> {
445        run_structural_mutator(root, self)
446    }
447}
448
449/// Convert a mutation callback result into [`Result<Any>`].
450///
451/// A callback may return any value convertible into [`Any`], or wrap it in
452/// [`Result`] to use `?`.
453#[doc(hidden)]
454pub trait IntoMutateResult: callback_result_sealed::Sealed {
455    fn into_mutate_result(self) -> Result<Any>;
456}
457
458impl<T: Into<Any>> IntoMutateResult for T {
459    #[inline]
460    fn into_mutate_result(self) -> Result<Any> {
461        Ok(self.into())
462    }
463}
464
465impl<T: Into<Any>> IntoMutateResult for Result<T> {
466    #[inline]
467    fn into_mutate_result(self) -> Result<Any> {
468        self.map(Into::into)
469    }
470}
471
472#[doc(hidden)]
473pub type MutateResult = Result<Any>;
474
475#[doc(hidden)]
476/// Callback tuples use a type-erased mutation driver.
477pub enum DynamicMutateCallbacks {}
478
479/// One typed callback in a callback-driven structural mutator.
480pub trait MutateChainLink<State, Marker>: mutate_sealed::SealedLink<State, Marker> {
481    #[doc(hidden)]
482    type Strategy;
483
484    #[doc(hidden)]
485    fn try_mutate(
486        &self,
487        value: &MapValue,
488        mutator: &mut MutateContext<'_, State>,
489    ) -> Option<MutateResult>;
490}
491
492/// Ordered typed callback dispatch for [`structural_mutate`].
493///
494/// `None` means no handler matched, so structural mutation applies its default
495/// behavior. A generated `#[dispatch(mutate)]` implementation tests
496/// `mutate_*` methods in source order and passes the same [`Mutator`] to the
497/// first match. The implementation owns its pass state and receives `&mut
498/// self`, while [`Mutator`] only controls recursion and the definition region.
499pub trait MutateDispatch: Sized {
500    fn dispatch_mutate(&mut self, value: &MapValue, mutator: &mut Mutator) -> Option<MutateResult>;
501}
502
503impl<D: MutateDispatch> IntoMutator<ByMutateDispatch> for D {
504    #[inline]
505    fn mutate_root(mut self, root: Any) -> Result<Any> {
506        run_structural_mutator(root, &mut self)
507    }
508}
509
510mod mutate_sealed {
511    use super::{IntoMutateResult, MapValue, MutateContext, ObjectCore};
512
513    pub trait SealedLink<State, Marker> {}
514
515    impl<F, State, T, O> SealedLink<State, super::ByMutateOwned<T>> for F
516    where
517        F: for<'mutator, 'driver> Fn(T, &'mutator mut MutateContext<'driver, State>) -> O,
518        O: IntoMutateResult,
519    {
520    }
521
522    impl<F, State, N: ObjectCore, O> SealedLink<State, super::ByMutateNode<N>> for F
523    where
524        F: for<'value, 'mutator, 'driver> Fn(
525            &'value N,
526            &'mutator mut MutateContext<'driver, State>,
527        ) -> O,
528        O: IntoMutateResult,
529    {
530    }
531
532    impl<F, State, O> SealedLink<State, super::ByMutateCatchAll> for F
533    where
534        F: for<'value, 'mutator, 'driver> Fn(
535            &'value MapValue,
536            &'mutator mut MutateContext<'driver, State>,
537        ) -> O,
538        O: IntoMutateResult,
539    {
540    }
541}
542
543#[doc(hidden)]
544pub enum ByMutateDispatch {}
545
546#[doc(hidden)]
547pub struct ByMutateOwned<T>(PhantomData<T>);
548
549impl<F, State, T, O> MutateChainLink<State, ByMutateOwned<T>> for F
550where
551    F: for<'mutator, 'driver> Fn(T, &'mutator mut MutateContext<'driver, State>) -> O,
552    T: crate::type_traits::AnyCompatible,
553    O: IntoMutateResult,
554{
555    type Strategy = DynamicMutateCallbacks;
556
557    fn try_mutate(
558        &self,
559        value: &MapValue,
560        mutator: &mut MutateContext<'_, State>,
561    ) -> Option<MutateResult> {
562        value
563            .cast::<T>()
564            .map(|typed| self(typed, mutator).into_mutate_result())
565    }
566}
567
568#[doc(hidden)]
569pub struct ByMutateNode<N>(PhantomData<N>);
570
571impl<F, State, N, O> MutateChainLink<State, ByMutateNode<N>> for F
572where
573    F: for<'value, 'mutator, 'driver> Fn(
574        &'value N,
575        &'mutator mut MutateContext<'driver, State>,
576    ) -> O,
577    N: ObjectCore,
578    O: IntoMutateResult,
579{
580    type Strategy = DynamicMutateCallbacks;
581
582    fn try_mutate(
583        &self,
584        value: &MapValue,
585        mutator: &mut MutateContext<'_, State>,
586    ) -> Option<MutateResult> {
587        value
588            .as_node::<N>()
589            .map(|node| self(node, mutator).into_mutate_result())
590    }
591}
592
593#[doc(hidden)]
594pub enum ByMutateCatchAll {}
595
596impl<F, State, O> MutateChainLink<State, ByMutateCatchAll> for F
597where
598    F: for<'value, 'mutator, 'driver> Fn(
599        &'value MapValue,
600        &'mutator mut MutateContext<'driver, State>,
601    ) -> O,
602    O: IntoMutateResult,
603{
604    type Strategy = DynamicMutateCallbacks;
605
606    fn try_mutate(
607        &self,
608        value: &MapValue,
609        mutator: &mut MutateContext<'_, State>,
610    ) -> Option<MutateResult> {
611        Some(self(value, mutator).into_mutate_result())
612    }
613}
614
615#[doc(hidden)]
616pub struct ByMutateChainLink<Markers>(PhantomData<fn(Markers)>);
617
618macro_rules! impl_mutate_chain_link {
619    ($(($F:ident, $M:ident, $idx:tt)),+) => {
620        impl<State, $($F, $M,)+>
621            mutate_sealed::SealedLink<State, ByMutateChainLink<($($M,)+)>> for ($($F,)+)
622        where
623            $($F: MutateChainLink<State, $M>,)+
624        {
625        }
626
627        impl<State, $($F, $M,)+> MutateChainLink<State, ByMutateChainLink<($($M,)+)>>
628            for ($($F,)+)
629        where
630            $($F: MutateChainLink<State, $M>,)+
631        {
632            type Strategy = DynamicMutateCallbacks;
633
634            fn try_mutate(
635                &self,
636                value: &MapValue,
637                mutator: &mut MutateContext<'_, State>,
638            ) -> Option<MutateResult> {
639                $(
640                    if let Some(result) = self.$idx.try_mutate(value, mutator) {
641                        return Some(result);
642                    }
643                )+
644                None
645            }
646        }
647    };
648}
649
650impl_callback_chain_tuple_arities!(impl_mutate_chain_link);
651
652/// A reusable typed-dispatch or callback mutator with shared user state.
653pub struct MutateCallbacks<State, Link, Marker> {
654    state: State,
655    callbacks: Rc<Link>,
656    _marker: PhantomData<fn(Marker)>,
657}
658
659impl<State, Link, Marker> MutateCallbacks<State, Link, Marker>
660where
661    Link: MutateChainLink<State, Marker>,
662{
663    /// Construct a stateful callback mutator.
664    pub fn new(state: State, callbacks: Link) -> Self {
665        Self {
666            state,
667            callbacks: Rc::new(callbacks),
668            _marker: PhantomData,
669        }
670    }
671}
672
673impl<State, Link, Marker> MutateCallbacks<State, Link, Marker> {
674    /// Shared access to the callback state.
675    pub fn state(&self) -> &State {
676        &self.state
677    }
678
679    /// Mutable access to callback state outside an active recursive call.
680    pub fn state_mut(&mut self) -> &mut State {
681        &mut self.state
682    }
683
684    /// Consume the mutator and return its state.
685    pub fn into_state(self) -> State {
686        self.state
687    }
688}
689
690struct DirectMutateCallbacks<'a, Link, Marker> {
691    state: (),
692    callbacks: &'a Link,
693    _marker: PhantomData<fn(Marker)>,
694}
695
696trait MutateCallbackState<State> {
697    fn callback_state(&self) -> &State;
698    fn callback_state_mut(&mut self) -> &mut State;
699}
700
701impl<State, Link, Marker> MutateCallbackState<State> for MutateCallbacks<State, Link, Marker> {
702    fn callback_state(&self) -> &State {
703        &self.state
704    }
705
706    fn callback_state_mut(&mut self) -> &mut State {
707        &mut self.state
708    }
709}
710
711impl<Link, Marker> MutateCallbackState<()> for DirectMutateCallbacks<'_, Link, Marker> {
712    fn callback_state(&self) -> &() {
713        &self.state
714    }
715
716    fn callback_state_mut(&mut self) -> &mut () {
717        &mut self.state
718    }
719}
720
721#[doc(hidden)]
722pub struct ByMutateCallbacks<Marker>(PhantomData<fn(Marker)>);
723
724impl<Link, Marker> IntoMutator<ByMutateCallbacks<Marker>> for Link
725where
726    Link: MutateChainLink<(), Marker>,
727    Link::Strategy: MutateCallbackStrategy<(), Link, Marker>,
728{
729    fn mutate_root(self, root: Any) -> Result<Any> {
730        let callbacks = self;
731        let mut mutator = DirectMutateCallbacks::<Link, Marker> {
732            state: (),
733            callbacks: &callbacks,
734            _marker: PhantomData,
735        };
736        run_structural_mutator(root, &mut mutator)
737    }
738}
739
740/// Ordered typed replacement dispatch for [`structural_map`].
741///
742/// `None` means no handler matched and preserves the current value.  A
743/// generated `#[dispatch(map)]` implementation tests `map_*` methods in
744/// source order and returns the first match.
745pub trait MapDispatch: Sized {
746    fn dispatch_map(
747        &mut self,
748        value: &MapValue,
749        def_region_kind: DefRegionKind,
750    ) -> Option<MapResult>;
751}
752
753impl<V: MapDispatch> MapDispatch for &mut V {
754    #[inline]
755    fn dispatch_map(
756        &mut self,
757        value: &MapValue,
758        def_region_kind: DefRegionKind,
759    ) -> Option<MapResult> {
760        (**self).dispatch_map(value, def_region_kind)
761    }
762}
763
764/// Conversion into the mapper consumed by [`structural_map`].
765#[diagnostic::on_unimplemented(
766    message = "unsupported structural-map callback shape",
767    label = "this value cannot be used as a structural mapper",
768    note = "pass `&mut` a type implementing `MapDispatch`, a supported closure, or a tuple of callbacks"
769)]
770pub trait IntoMapper<Marker> {
771    type Mapper: MapDispatch;
772    fn into_mapper(self) -> Self::Mapper;
773}
774
775#[doc(hidden)]
776pub enum ByMapDispatch {}
777
778impl<'a, V: MapDispatch> IntoMapper<ByMapDispatch> for &'a mut V {
779    type Mapper = &'a mut V;
780
781    #[inline]
782    fn into_mapper(self) -> Self::Mapper {
783        self
784    }
785}
786
787/// One typed callback in a structural-map tuple.
788///
789/// Links use first-match order and may receive an owned FFI value, borrowed
790/// object node, or `&MapValue`, optionally followed by [`DefRegionKind`].
791pub trait MapChainLink<Marker>: sealed_map::SealedMapLink<Marker> {
792    #[doc(hidden)]
793    fn try_map(&mut self, value: &MapValue, def_region_kind: DefRegionKind) -> Option<MapResult>;
794}
795
796mod sealed_map {
797    use super::{DefRegionKind, IntoMapResult, MapDispatch, MapValue, ObjectCore};
798
799    pub trait SealedMapLink<Marker> {}
800
801    impl<F, T, O> SealedMapLink<super::ByMapOwned<T>> for F
802    where
803        F: FnMut(T) -> O,
804        O: IntoMapResult,
805    {
806    }
807
808    impl<F, T, O> SealedMapLink<super::ByMapOwnedKind<T>> for F
809    where
810        F: FnMut(T, DefRegionKind) -> O,
811        O: IntoMapResult,
812    {
813    }
814
815    impl<F, N: ObjectCore, O> SealedMapLink<super::ByMapNode<N>> for F
816    where
817        F: for<'a> FnMut(&'a N) -> O,
818        O: IntoMapResult,
819    {
820    }
821
822    impl<F, N: ObjectCore, O> SealedMapLink<super::ByMapNodeKind<N>> for F
823    where
824        F: for<'a> FnMut(&'a N, DefRegionKind) -> O,
825        O: IntoMapResult,
826    {
827    }
828
829    impl<F, O> SealedMapLink<super::ByMapCatchAll> for F
830    where
831        F: for<'a> FnMut(&'a MapValue) -> O,
832        O: IntoMapResult,
833    {
834    }
835
836    impl<F, O> SealedMapLink<super::ByMapCatchAllKind> for F
837    where
838        F: for<'a> FnMut(&'a MapValue, DefRegionKind) -> O,
839        O: IntoMapResult,
840    {
841    }
842
843    impl<V: MapDispatch> SealedMapLink<super::ByMapDispatchLink> for &mut V {}
844}
845
846#[doc(hidden)]
847pub struct ByMapOwned<T>(PhantomData<T>);
848
849impl<F, T, O> MapChainLink<ByMapOwned<T>> for F
850where
851    F: FnMut(T) -> O,
852    T: crate::type_traits::AnyCompatible,
853    O: IntoMapResult,
854{
855    #[inline]
856    fn try_map(&mut self, value: &MapValue, _def_region_kind: DefRegionKind) -> Option<MapResult> {
857        value.cast::<T>().map(|typed| self(typed).into_map_result())
858    }
859}
860
861#[doc(hidden)]
862pub struct ByMapOwnedKind<T>(PhantomData<T>);
863
864impl<F, T, O> MapChainLink<ByMapOwnedKind<T>> for F
865where
866    F: FnMut(T, DefRegionKind) -> O,
867    T: crate::type_traits::AnyCompatible,
868    O: IntoMapResult,
869{
870    #[inline]
871    fn try_map(&mut self, value: &MapValue, def_region_kind: DefRegionKind) -> Option<MapResult> {
872        value
873            .cast::<T>()
874            .map(|typed| self(typed, def_region_kind).into_map_result())
875    }
876}
877
878#[doc(hidden)]
879pub struct ByMapNode<N>(PhantomData<N>);
880
881impl<F, N, O> MapChainLink<ByMapNode<N>> for F
882where
883    F: for<'a> FnMut(&'a N) -> O,
884    N: ObjectCore,
885    O: IntoMapResult,
886{
887    #[inline]
888    fn try_map(&mut self, value: &MapValue, _def_region_kind: DefRegionKind) -> Option<MapResult> {
889        value
890            .as_node::<N>()
891            .map(|node| self(node).into_map_result())
892    }
893}
894
895#[doc(hidden)]
896pub struct ByMapNodeKind<N>(PhantomData<N>);
897
898impl<F, N, O> MapChainLink<ByMapNodeKind<N>> for F
899where
900    F: for<'a> FnMut(&'a N, DefRegionKind) -> O,
901    N: ObjectCore,
902    O: IntoMapResult,
903{
904    #[inline]
905    fn try_map(&mut self, value: &MapValue, def_region_kind: DefRegionKind) -> Option<MapResult> {
906        value
907            .as_node::<N>()
908            .map(|node| self(node, def_region_kind).into_map_result())
909    }
910}
911
912#[doc(hidden)]
913pub enum ByMapCatchAll {}
914
915impl<F, O> MapChainLink<ByMapCatchAll> for F
916where
917    F: for<'a> FnMut(&'a MapValue) -> O,
918    O: IntoMapResult,
919{
920    #[inline]
921    fn try_map(&mut self, value: &MapValue, _def_region_kind: DefRegionKind) -> Option<MapResult> {
922        Some(self(value).into_map_result())
923    }
924}
925
926#[doc(hidden)]
927pub enum ByMapCatchAllKind {}
928
929impl<F, O> MapChainLink<ByMapCatchAllKind> for F
930where
931    F: for<'a> FnMut(&'a MapValue, DefRegionKind) -> O,
932    O: IntoMapResult,
933{
934    #[inline]
935    fn try_map(&mut self, value: &MapValue, def_region_kind: DefRegionKind) -> Option<MapResult> {
936        Some(self(value, def_region_kind).into_map_result())
937    }
938}
939
940#[doc(hidden)]
941pub struct ByMapChainLink<Markers>(PhantomData<fn(Markers)>);
942
943#[doc(hidden)]
944pub enum ByMapDispatchLink {}
945
946impl<V: MapDispatch> MapChainLink<ByMapDispatchLink> for &mut V {
947    #[inline]
948    fn try_map(&mut self, value: &MapValue, def_region_kind: DefRegionKind) -> Option<MapResult> {
949        self.dispatch_map(value, def_region_kind)
950    }
951}
952
953/// Adapter from a [`MapChainLink`] to [`MapDispatch`].
954#[doc(hidden)]
955pub struct MapChain<Link, Marker> {
956    link: Link,
957    marker: PhantomData<fn(Marker)>,
958}
959
960impl<Link, Marker> MapChain<Link, Marker> {
961    #[inline]
962    fn new(link: Link) -> Self {
963        MapChain {
964            link,
965            marker: PhantomData,
966        }
967    }
968}
969
970impl<Link, Marker> MapDispatch for MapChain<Link, Marker>
971where
972    Link: MapChainLink<Marker>,
973{
974    #[inline]
975    fn dispatch_map(
976        &mut self,
977        value: &MapValue,
978        def_region_kind: DefRegionKind,
979    ) -> Option<MapResult> {
980        self.link.try_map(value, def_region_kind)
981    }
982}
983
984macro_rules! impl_map_chain_link {
985    ($(($F:ident, $M:ident, $idx:tt)),+) => {
986        impl<$($F, $M,)+> sealed_map::SealedMapLink<ByMapChainLink<($($M,)+)>> for ($($F,)+)
987        where
988            $($F: MapChainLink<$M>,)+
989        {
990        }
991
992        impl<$($F, $M,)+> MapChainLink<ByMapChainLink<($($M,)+)>> for ($($F,)+)
993        where
994            $($F: MapChainLink<$M>,)+
995        {
996            #[inline]
997            fn try_map(
998                &mut self,
999                value: &MapValue,
1000                def_region_kind: DefRegionKind,
1001            ) -> Option<MapResult> {
1002                $(
1003                    if let Some(result) = self.$idx.try_map(value, def_region_kind) {
1004                        return Some(result);
1005                    }
1006                )+
1007                None
1008            }
1009        }
1010
1011        impl<$($F, $M,)+> IntoMapper<($($M,)+)> for ($($F,)+)
1012        where
1013            $($F: MapChainLink<$M>,)+
1014        {
1015            type Mapper = MapChain<($($F,)+), ByMapChainLink<($($M,)+)>>;
1016
1017            #[inline]
1018            fn into_mapper(self) -> Self::Mapper {
1019                MapChain::new(self)
1020            }
1021        }
1022    };
1023}
1024
1025impl_callback_chain_tuple_arities!(impl_map_chain_link);
1026
1027macro_rules! impl_bare_map_link {
1028    ($(($marker:ident, $($fn_args:ty),+)),+ $(,)?) => {
1029        $(
1030            impl<F, T, O> IntoMapper<$marker<T>> for F
1031            where
1032                F: FnMut($($fn_args),+) -> O,
1033                Self: MapChainLink<$marker<T>>,
1034                O: IntoMapResult,
1035            {
1036                type Mapper = MapChain<F, $marker<T>>;
1037
1038                #[inline]
1039                fn into_mapper(self) -> Self::Mapper {
1040                    MapChain::new(self)
1041                }
1042            }
1043        )+
1044    };
1045}
1046
1047impl_bare_map_link!(
1048    (ByMapOwned, T),
1049    (ByMapOwnedKind, T, DefRegionKind),
1050    (ByMapNode, &T),
1051    (ByMapNodeKind, &T, DefRegionKind),
1052);
1053
1054impl<F, O> IntoMapper<ByMapCatchAll> for F
1055where
1056    F: for<'a> FnMut(&'a MapValue) -> O,
1057    O: IntoMapResult,
1058{
1059    type Mapper = MapChain<F, ByMapCatchAll>;
1060
1061    #[inline]
1062    fn into_mapper(self) -> Self::Mapper {
1063        MapChain::new(self)
1064    }
1065}
1066
1067impl<F, O> IntoMapper<ByMapCatchAllKind> for F
1068where
1069    F: for<'a> FnMut(&'a MapValue, DefRegionKind) -> O,
1070    O: IntoMapResult,
1071{
1072    type Mapper = MapChain<F, ByMapCatchAllKind>;
1073
1074    #[inline]
1075    fn into_mapper(self) -> Self::Mapper {
1076        MapChain::new(self)
1077    }
1078}
1079
1080/// Engine-issued permission to attempt in-place mutation of one value.
1081///
1082/// The engine issues it only when the current ownership path permits reuse.
1083pub struct InplaceValue<'a> {
1084    value: MapValue,
1085    _scope: PhantomData<&'a mut TVMFFIAny>,
1086}
1087
1088impl<'a> InplaceValue<'a> {
1089    #[inline]
1090    fn from_raw(raw: &'a mut TVMFFIAny) -> Self {
1091        Self {
1092            value: MapValue::from_raw(*raw),
1093            _scope: PhantomData,
1094        }
1095    }
1096
1097    /// Borrow the value without its in-place capability.
1098    #[inline]
1099    pub fn as_value(&self) -> &MapValue {
1100        &self.value
1101    }
1102
1103    /// Retain an owning copy of the value.
1104    ///
1105    /// Retaining an object creates an alias. The default in-place helper
1106    /// rechecks uniqueness and automatically falls back to copying.
1107    #[inline]
1108    pub fn to_owned(&self) -> Any {
1109        self.value.to_owned()
1110    }
1111}
1112
1113impl Deref for InplaceValue<'_> {
1114    type Target = MapValue;
1115
1116    #[inline]
1117    fn deref(&self) -> &Self::Target {
1118        self.as_value()
1119    }
1120}
1121
1122/// Identity substitutions for a custom [`StructuralMutator`] remapping policy.
1123///
1124/// The map owns its keys and values so object addresses remain stable.
1125#[derive(Default)]
1126pub struct StructuralVarRemap {
1127    entries: HashMap<NonNull<TVMFFIObject>, MemoEntry>,
1128}
1129
1130impl StructuralVarRemap {
1131    /// Look up an identity replacement previously stored for `var`.
1132    pub fn get(&self, var: &MapValue) -> Result<Option<Any>> {
1133        let key = object_identity_key(var.raw())?;
1134        Ok(self.entries.get(&key).map(|entry| entry.result.clone()))
1135    }
1136
1137    /// Store a descent result or an [`Unchanged`] marker for `var`.
1138    pub fn set(&mut self, var: &MapValue, mutated_value: &Any) -> Result<()> {
1139        let key = object_identity_key(var.raw())?;
1140        self.entries.insert(
1141            key,
1142            MemoEntry {
1143                _original: var.to_owned(),
1144                result: mutated_value.clone(),
1145            },
1146        );
1147        Ok(())
1148    }
1149
1150    /// Remove every recorded identity substitution.
1151    pub fn clear(&mut self) {
1152        self.entries.clear();
1153    }
1154}
1155
1156/// A low-level mutator that controls its own recursion.
1157///
1158/// Implementations descend with the `mutate` or `default_*` helpers.
1159/// Prefer mutation callbacks or `#[dispatch(mutate)]` for typed dispatch with
1160/// recursion supplied through [`Mutator`].
1161pub trait StructuralMutator: Sized {
1162    /// Dispatch one borrowed value without modifying its source storage.
1163    ///
1164    /// The structural-mutation engine calls this hook for each value.
1165    fn dispatch_mutate(&mut self, value: &MapValue, def_region_kind: DefRegionKind) -> Result<Any>;
1166
1167    /// Dispatch one value for which the engine permits an in-place attempt.
1168    ///
1169    /// The default delegates to [`Self::dispatch_mutate`] and therefore remains
1170    /// non-in-place. Override this method to opt into the default container
1171    /// reuse path.
1172    fn dispatch_maybe_inplace_mutate(
1173        &mut self,
1174        value: InplaceValue<'_>,
1175        def_region_kind: DefRegionKind,
1176    ) -> Result<Any> {
1177        self.dispatch_mutate(value.as_value(), def_region_kind)
1178    }
1179
1180    /// Re-enter this mutator for a borrowed value. The value and all of its
1181    /// descendants use the non-in-place path.
1182    fn mutate<T>(&mut self, value: &T, def_region_kind: DefRegionKind) -> Result<Any>
1183    where
1184        for<'x> AnyView<'x>: From<&'x T>,
1185    {
1186        let view = AnyView::from(value);
1187        dispatch_user_raw(self, *view.as_raw_ffi_any(), def_region_kind, Permit::Copy)
1188            .and_then(|result| resolve_result(result, *view.as_raw_ffi_any()))
1189    }
1190
1191    /// Re-enter this mutator for an owned value, permitting reuse only when
1192    /// the converted value remains uniquely owned.
1193    fn maybe_inplace_mutate<T>(&mut self, value: T, def_region_kind: DefRegionKind) -> Result<Any>
1194    where
1195        T: Into<Any>,
1196    {
1197        let value = value.into();
1198        let result = dispatch_user_raw(
1199            self,
1200            *value.as_raw_ffi_any(),
1201            def_region_kind,
1202            Permit::MaybeInPlace,
1203        )?;
1204        Ok(if is_unchanged(&result) { value } else { result })
1205    }
1206
1207    /// Apply default non-in-place mutation to `value`'s children.
1208    fn default_mutate(&mut self, value: &MapValue, def_region_kind: DefRegionKind) -> Result<Any> {
1209        user_default_mutate(self, value.raw(), def_region_kind, Permit::Copy)
1210            .and_then(|result| resolve_result(result, value.raw()))
1211    }
1212
1213    /// Apply default non-in-place mutation to a borrowed typed value.
1214    ///
1215    /// Unlike [Self::mutate], this bypasses dispatch for the value
1216    /// itself while its children still re-enter this mutator. This lets a
1217    /// typed structural-mutate handler recurse through its current node
1218    /// before applying a post-order rewrite.
1219    fn default_mutate_value<T>(&mut self, value: &T, def_region_kind: DefRegionKind) -> Result<Any>
1220    where
1221        for<'x> AnyView<'x>: From<&'x T>,
1222    {
1223        let view = AnyView::from(value);
1224        user_default_mutate(self, *view.as_raw_ffi_any(), def_region_kind, Permit::Copy)
1225            .and_then(|result| resolve_result(result, *view.as_raw_ffi_any()))
1226    }
1227
1228    /// Apply the default mutation under an engine-issued in-place capability.
1229    ///
1230    /// Uniqueness is checked again here because user code may have retained
1231    /// an owning alias after the capability was issued.
1232    fn default_maybe_inplace_mutate(
1233        &mut self,
1234        value: InplaceValue<'_>,
1235        def_region_kind: DefRegionKind,
1236    ) -> Result<Any> {
1237        let raw = value.raw();
1238        let permit = if object_is_unique(raw) {
1239            Permit::MaybeInPlace
1240        } else {
1241            Permit::Copy
1242        };
1243        user_default_mutate(self, raw, def_region_kind, permit)
1244            .and_then(|result| resolve_result(result, raw))
1245    }
1246
1247    /// Re-enter this mutator for a borrowed value, preserving unchanged.
1248    fn mutate_result<T>(&mut self, value: &T, kind: DefRegionKind) -> Result<UnchangedOr<Any>>
1249    where
1250        for<'x> AnyView<'x>: From<&'x T>,
1251    {
1252        let view = AnyView::from(value);
1253        dispatch_user_raw(self, *view.as_raw_ffi_any(), kind, Permit::Copy)
1254            .and_then(UnchangedOr::from_carrier)
1255    }
1256
1257    /// Default non-in-place mutation with an unchanged-or-replacement result.
1258    fn default_mutate_result(
1259        &mut self,
1260        value: &MapValue,
1261        kind: DefRegionKind,
1262    ) -> Result<UnchangedOr<Any>> {
1263        user_default_mutate(self, value.raw(), kind, Permit::Copy)
1264            .and_then(UnchangedOr::from_carrier)
1265    }
1266
1267    /// Default mutation of a borrowed typed value, preserving unchanged.
1268    fn default_mutate_value_result<T>(
1269        &mut self,
1270        value: &T,
1271        kind: DefRegionKind,
1272    ) -> Result<UnchangedOr<Any>>
1273    where
1274        for<'x> AnyView<'x>: From<&'x T>,
1275    {
1276        let view = AnyView::from(value);
1277        user_default_mutate(self, *view.as_raw_ffi_any(), kind, Permit::Copy)
1278            .and_then(UnchangedOr::from_carrier)
1279    }
1280
1281    /// Default mutation under an engine-issued capability, preserving unchanged.
1282    fn default_maybe_inplace_mutate_result(
1283        &mut self,
1284        value: InplaceValue<'_>,
1285        kind: DefRegionKind,
1286    ) -> Result<UnchangedOr<Any>> {
1287        let raw = value.raw();
1288        let permit = if object_is_unique(raw) {
1289            Permit::MaybeInPlace
1290        } else {
1291            Permit::Copy
1292        };
1293        user_default_mutate(self, raw, kind, permit).and_then(UnchangedOr::from_carrier)
1294    }
1295
1296    /// Look up a FreeVar or DAG-node substitution from the active mutation.
1297    fn var_remap_get(&mut self, var: &MapValue) -> Result<Option<Any>> {
1298        invocation_var_remap_get(self, var)
1299    }
1300
1301    /// Store a FreeVar or DAG-node substitution for the active mutation.
1302    fn var_remap_set(&mut self, var: &MapValue, mutated_value: &Any) -> Result<()> {
1303        invocation_var_remap_set(self, var, mutated_value)
1304    }
1305}
1306
1307impl<D: MutateDispatch> StructuralMutator for D {
1308    #[inline(always)]
1309    fn dispatch_mutate(&mut self, value: &MapValue, def_region_kind: DefRegionKind) -> Result<Any> {
1310        let mut mutator = Mutator {
1311            current: MapValue::from_raw(value.raw()),
1312            def_region_kind,
1313            _not_send_sync: PhantomData,
1314        };
1315        match MutateDispatch::dispatch_mutate(self, value, &mut mutator) {
1316            Some(result) => result,
1317            None => user_default_mutate(self, value.raw(), def_region_kind, Permit::Copy),
1318        }
1319    }
1320
1321    #[inline(always)]
1322    fn dispatch_maybe_inplace_mutate(
1323        &mut self,
1324        value: InplaceValue<'_>,
1325        def_region_kind: DefRegionKind,
1326    ) -> Result<Any> {
1327        let mut mutator = Mutator {
1328            current: MapValue::from_raw(value.raw()),
1329            def_region_kind,
1330            _not_send_sync: PhantomData,
1331        };
1332        match MutateDispatch::dispatch_mutate(self, value.as_value(), &mut mutator) {
1333            Some(result) => result,
1334            None => {
1335                let raw = value.raw();
1336                let permit = if object_is_unique(raw) {
1337                    Permit::MaybeInPlace
1338                } else {
1339                    Permit::Copy
1340                };
1341                user_default_mutate(self, raw, def_region_kind, permit)
1342            }
1343        }
1344    }
1345}
1346
1347// Closure callback chains use a type-erased context driver so one concrete
1348// function signature can recurse through the complete chain.
1349trait MutateCallbackStrategy<State, Link, Marker> {
1350    fn try_mutate<Driver>(
1351        driver: &mut Driver,
1352        callback_ptr: *const Link,
1353        value: &MapValue,
1354        def_region_kind: DefRegionKind,
1355    ) -> Option<MutateResult>
1356    where
1357        Driver: MutateContextDriver<State>;
1358}
1359
1360impl<State, Link, Marker> MutateCallbackStrategy<State, Link, Marker> for DynamicMutateCallbacks
1361where
1362    Link: MutateChainLink<State, Marker>,
1363{
1364    #[inline(always)]
1365    fn try_mutate<Driver>(
1366        driver: &mut Driver,
1367        callback_ptr: *const Link,
1368        value: &MapValue,
1369        def_region_kind: DefRegionKind,
1370    ) -> Option<MutateResult>
1371    where
1372        Driver: MutateContextDriver<State>,
1373    {
1374        let mut mutator = MutateContext::<State, dyn MutateContextDriver<State>> {
1375            driver,
1376            current: MapValue::from_raw(value.raw()),
1377            def_region_kind,
1378            _state: PhantomData,
1379            _not_send_sync: PhantomData,
1380        };
1381        // SAFETY: The owning `Rc` or the direct callback's stack slot remains live
1382        // and is never modified through the driver during recursive reentry.
1383        unsafe { (&*callback_ptr).try_mutate(value, &mut mutator) }
1384    }
1385}
1386
1387#[inline(always)]
1388fn try_mutate_callbacks<State, Link, Marker, Driver>(
1389    driver: &mut Driver,
1390    callback_ptr: *const Link,
1391    value: &MapValue,
1392    def_region_kind: DefRegionKind,
1393) -> Option<MutateResult>
1394where
1395    Link: MutateChainLink<State, Marker>,
1396    Link::Strategy: MutateCallbackStrategy<State, Link, Marker>,
1397    Driver: MutateContextDriver<State>,
1398{
1399    <Link::Strategy as MutateCallbackStrategy<State, Link, Marker>>::try_mutate(
1400        driver,
1401        callback_ptr,
1402        value,
1403        def_region_kind,
1404    )
1405}
1406
1407impl<State, Link, Marker> StructuralMutator for MutateCallbacks<State, Link, Marker>
1408where
1409    Link: MutateChainLink<State, Marker>,
1410    Link::Strategy: MutateCallbackStrategy<State, Link, Marker>,
1411{
1412    #[inline(always)]
1413    fn dispatch_mutate(&mut self, value: &MapValue, def_region_kind: DefRegionKind) -> Result<Any> {
1414        let callback_ptr = Rc::as_ptr(&self.callbacks);
1415        match try_mutate_callbacks::<State, Link, Marker, _>(
1416            self,
1417            callback_ptr,
1418            value,
1419            def_region_kind,
1420        ) {
1421            Some(result) => result,
1422            None => user_default_mutate(self, value.raw(), def_region_kind, Permit::Copy),
1423        }
1424    }
1425
1426    #[inline(always)]
1427    fn dispatch_maybe_inplace_mutate(
1428        &mut self,
1429        value: InplaceValue<'_>,
1430        def_region_kind: DefRegionKind,
1431    ) -> Result<Any> {
1432        let callback_ptr = Rc::as_ptr(&self.callbacks);
1433        match try_mutate_callbacks::<State, Link, Marker, _>(
1434            self,
1435            callback_ptr,
1436            value.as_value(),
1437            def_region_kind,
1438        ) {
1439            Some(result) => result,
1440            None => self
1441                .default_maybe_inplace_mutate_result(value, def_region_kind)
1442                .map(Any::from),
1443        }
1444    }
1445}
1446
1447impl<Link, Marker> StructuralMutator for DirectMutateCallbacks<'_, Link, Marker>
1448where
1449    Link: MutateChainLink<(), Marker>,
1450    Link::Strategy: MutateCallbackStrategy<(), Link, Marker>,
1451{
1452    #[inline(always)]
1453    fn dispatch_mutate(&mut self, value: &MapValue, def_region_kind: DefRegionKind) -> Result<Any> {
1454        let callback_ptr = std::ptr::from_ref(self.callbacks);
1455        match try_mutate_callbacks::<(), Link, Marker, _>(
1456            self,
1457            callback_ptr,
1458            value,
1459            def_region_kind,
1460        ) {
1461            Some(result) => result,
1462            None => user_default_mutate(self, value.raw(), def_region_kind, Permit::Copy),
1463        }
1464    }
1465
1466    #[inline(always)]
1467    fn dispatch_maybe_inplace_mutate(
1468        &mut self,
1469        value: InplaceValue<'_>,
1470        def_region_kind: DefRegionKind,
1471    ) -> Result<Any> {
1472        let callback_ptr = std::ptr::from_ref(self.callbacks);
1473        match try_mutate_callbacks::<(), Link, Marker, _>(
1474            self,
1475            callback_ptr,
1476            value.as_value(),
1477            def_region_kind,
1478        ) {
1479            Some(result) => result,
1480            None => self
1481                .default_maybe_inplace_mutate_result(value, def_region_kind)
1482                .map(Any::from),
1483        }
1484    }
1485}
1486
1487impl<State, Driver> MutateContextDriver<State> for Driver
1488where
1489    Driver: StructuralMutator + MutateCallbackState<State>,
1490{
1491    #[inline(always)]
1492    fn state(&self) -> &State {
1493        self.callback_state()
1494    }
1495
1496    #[inline(always)]
1497    fn state_mut(&mut self) -> &mut State {
1498        self.callback_state_mut()
1499    }
1500
1501    #[inline(always)]
1502    fn mutate_raw(
1503        &mut self,
1504        raw: TVMFFIAny,
1505        def_region_kind: DefRegionKind,
1506        permit: Permit,
1507    ) -> Result<Any> {
1508        dispatch_user_raw(self, raw, def_region_kind, permit)
1509    }
1510
1511    #[inline(always)]
1512    fn default_mutate_raw(
1513        &mut self,
1514        raw: TVMFFIAny,
1515        def_region_kind: DefRegionKind,
1516    ) -> Result<Any> {
1517        default_mutate_driver(self, raw, def_region_kind, Permit::Copy)
1518    }
1519
1520    #[inline(always)]
1521    fn var_remap_get_raw(&mut self, raw: TVMFFIAny) -> Result<Option<Any>> {
1522        <Self as StructuralMutator>::var_remap_get(self, &MapValue::from_raw(raw))
1523    }
1524
1525    #[inline(always)]
1526    fn var_remap_set_raw(&mut self, raw: TVMFFIAny, mutated_value: &Any) -> Result<()> {
1527        <Self as StructuralMutator>::var_remap_set(self, &MapValue::from_raw(raw), mutated_value)
1528    }
1529}
1530
1531#[doc(hidden)]
1532#[derive(Clone, Copy, PartialEq, Eq)]
1533pub enum Permit {
1534    Copy,
1535    MaybeInPlace,
1536}
1537
1538struct MemoEntry {
1539    // Keeps the pointer-valued key alive so its address cannot be reused
1540    // during the same mapping invocation.
1541    _original: Any,
1542    result: Any,
1543}
1544
1545struct NativeMapper<D> {
1546    dispatch: D,
1547    order: WalkOrder,
1548    remap: StructuralVarRemap,
1549}
1550
1551impl<D: MapDispatch> NativeMapper<D> {
1552    fn map_raw(
1553        &mut self,
1554        raw: TVMFFIAny,
1555        def_region_kind: DefRegionKind,
1556        permit: Permit,
1557    ) -> Result<Any> {
1558        // Plain inline values have no children or structural identity.  Map
1559        // them directly instead of routing through identity lookup and the
1560        // default-mutation path, whose owning conversion crosses the C ABI.
1561        // Raw strings, byte-array views, and ObjectRValueRef are deliberately
1562        // excluded because converting those borrowed special values into an
1563        // Any performs normalization rather than a bitwise copy.
1564        if is_plain_inline(raw.type_index) {
1565            let value = MapValue::from_raw(raw);
1566            return match self.dispatch.dispatch_map(&value, def_region_kind) {
1567                Some(result) => {
1568                    let mapped = result?;
1569                    // A pre-order callback may replace an inline leaf with a subtree.
1570                    if self.order == WalkOrder::PreOrder && !is_plain_inline(mapped.type_index()) {
1571                        let descended =
1572                            self.map_default_root(&mapped, def_region_kind, Permit::MaybeInPlace)?;
1573                        Ok(if is_unchanged(&descended) {
1574                            mapped
1575                        } else {
1576                            descended
1577                        })
1578                    } else {
1579                        Ok(mapped)
1580                    }
1581                }
1582                // SAFETY: `is_plain_inline` excludes every borrowed
1583                // representation that needs normalization.  These values own
1584                // no external resource, so their owning form is the same
1585                // bitwise TVMFFIAny value.
1586                None => Ok(unsafe { Any::from_raw_ffi_any(raw) }),
1587            };
1588        }
1589
1590        self.map_current_raw(raw, def_region_kind, permit)
1591            .map_err(|error| with_value_context(error, raw))
1592    }
1593
1594    fn map_current_raw(
1595        &mut self,
1596        raw: TVMFFIAny,
1597        def_region_kind: DefRegionKind,
1598        permit: Permit,
1599    ) -> Result<Any> {
1600        match self.order {
1601            WalkOrder::PreOrder => {
1602                let value = MapValue::from_raw(raw);
1603                let Some(callback_result) = self.dispatch.dispatch_map(&value, def_region_kind)
1604                else {
1605                    return self.default_map_current_raw(raw, def_region_kind, permit);
1606                };
1607                let mapped = callback_result?;
1608                let mapped_raw = *mapped.as_raw_ffi_any();
1609                if is_unchanged(&mapped) || same_shallow(raw, mapped_raw) {
1610                    // Release the callback's temporary ownership before the
1611                    // runtime uniqueness check observes the original.
1612                    drop(mapped);
1613                    self.default_map_current_raw(raw, def_region_kind, permit)
1614                } else {
1615                    let descended =
1616                        self.map_default_root(&mapped, def_region_kind, Permit::MaybeInPlace)?;
1617                    Ok(if is_unchanged(&descended) {
1618                        mapped
1619                    } else {
1620                        descended
1621                    })
1622                }
1623            }
1624            WalkOrder::PostOrder => {
1625                let mapped = self.default_map_current_raw(raw, def_region_kind, permit)?;
1626                let mapped_raw = if is_unchanged(&mapped) {
1627                    raw
1628                } else {
1629                    *mapped.as_raw_ffi_any()
1630                };
1631                let value = MapValue::from_raw(mapped_raw);
1632                match self.dispatch.dispatch_map(&value, def_region_kind) {
1633                    Some(result) => result,
1634                    None => Ok(mapped),
1635                }
1636            }
1637        }
1638    }
1639
1640    /// Descend into a pre-order replacement without dispatching its root again.
1641    fn map_default_root(
1642        &mut self,
1643        mapped: &Any,
1644        def_region_kind: DefRegionKind,
1645        permit: Permit,
1646    ) -> Result<Any> {
1647        let raw = *mapped.as_raw_ffi_any();
1648        self.default_map_current_raw(raw, def_region_kind, permit)
1649            .map_err(|error| with_value_context(error, raw))
1650    }
1651}
1652
1653/// Internal mutation operations shared by the native mapper and a user
1654/// [`StructuralMutator`].
1655trait MutationDriver: Sized {
1656    fn dispatch_raw(
1657        &mut self,
1658        raw: TVMFFIAny,
1659        def_region_kind: DefRegionKind,
1660        permit: Permit,
1661    ) -> Result<Any>;
1662
1663    fn var_remap_get_raw(&mut self, raw: TVMFFIAny) -> Result<Option<Any>>;
1664
1665    fn var_remap_set_raw(&mut self, raw: TVMFFIAny, replacement: &Any) -> Result<()>;
1666
1667    fn call_registered_hook(
1668        &mut self,
1669        raw: TVMFFIAny,
1670        def_region_kind: DefRegionKind,
1671        permit: Permit,
1672    ) -> Result<Option<Any>> {
1673        let mutator = active_mutator()?;
1674        with_current_driver_context(mutator, self, || {
1675            call_registered_structural_mutate(mutator, raw, def_region_kind, permit)
1676        })
1677    }
1678
1679    fn default_map_current_raw(
1680        &mut self,
1681        raw: TVMFFIAny,
1682        def_region_kind: DefRegionKind,
1683        permit: Permit,
1684    ) -> Result<Any> {
1685        default_mutate_driver(self, raw, def_region_kind, permit)
1686    }
1687
1688    fn map_reflected(&mut self, raw: TVMFFIAny, def_region_kind: DefRegionKind) -> Result<Any> {
1689        let type_info = checked_type_info(raw.type_index)?;
1690        let seq_hash_kind = unsafe {
1691            if (*type_info).metadata.is_null() {
1692                TVMFFISEqHashKind::kTVMFFISEqHashKindUnsupported as i32
1693            } else {
1694                (*(*type_info).metadata).structural_eq_hash_kind
1695            }
1696        };
1697        let inherited_region = free_var_child_region(def_region_kind, seq_hash_kind);
1698        // Match the C++ reflected-mutation contract: resolve and invoke the
1699        // shallow-copy hook before inspecting any fields. Besides providing
1700        // isolated setter storage, this means a missing or failing hook is an
1701        // error even when no field eventually changes.
1702        let output = shallow_copy(raw)?;
1703        let output_raw = *output.as_raw_ffi_any();
1704        let output_object = unsafe { output_raw.data_union.v_obj.cast::<u8>() };
1705        if output_object.is_null() {
1706            return Err(runtime_error(
1707                "native structural map: shallow copy has a null object pointer",
1708            ));
1709        }
1710
1711        let mut field_changed = false;
1712        let mut failure: Option<Error> = None;
1713        unsafe {
1714            for_each_field_info(type_info, &mut |field| {
1715                if field.flags & FLAG_SEQ_HASH_IGNORE != 0 {
1716                    return ControlFlow::Continue(());
1717                }
1718                match self.map_reflected_field(
1719                    output_object,
1720                    field,
1721                    inherited_region,
1722                    &mut field_changed,
1723                ) {
1724                    Ok(()) => ControlFlow::Continue(()),
1725                    Err(error) => {
1726                        failure = Some(error);
1727                        ControlFlow::Break(())
1728                    }
1729                }
1730            });
1731        }
1732        if let Some(error) = failure {
1733            return Err(error);
1734        }
1735        if field_changed {
1736            Ok(output)
1737        } else {
1738            Ok(Unchanged.into())
1739        }
1740    }
1741
1742    unsafe fn map_reflected_field(
1743        &mut self,
1744        output_object: *mut u8,
1745        field: &TVMFFIFieldInfo,
1746        inherited_region: DefRegionKind,
1747        field_changed: &mut bool,
1748    ) -> Result<()> {
1749        let Some(getter) = field.getter else {
1750            return Err(runtime_error(&format!(
1751                "native structural map: reflected field `{}` has no getter",
1752                field.name.as_str()
1753            )));
1754        };
1755        // Read every field from the copy so earlier setters' side effects are
1756        // visible to later field mappings, exactly as in the C++ fallback.
1757        let field_offset = usize::try_from(field.offset).map_err(|_| {
1758            runtime_error(&format!(
1759                "native structural map: reflected field `{}` has an invalid offset",
1760                field.name.as_str()
1761            ))
1762        })?;
1763        // SAFETY: registered reflection metadata guarantees that the field
1764        // offset lies within this object's allocation. The checked conversion
1765        // above also prevents truncation on 32-bit targets.
1766        let source_address = output_object.add(field_offset).cast::<c_void>();
1767        // Own the output slot before entering foreign code. A getter may
1768        // populate an owning result and still report an error.
1769        let mut child = Any::new();
1770        if getter(source_address, Any::as_data_ptr(&mut child)) != 0 {
1771            return Err(with_error_context(
1772                Error::from_raised(),
1773                &format!("field `{}`", field.name.as_str()),
1774            ));
1775        }
1776        // Reflection getters return owning values. Keep the child alive for
1777        // the complete recursive call, then let normal Drop release it.
1778        let child_raw = *child.as_raw_ffi_any();
1779        let child_region = field_def_region(field, inherited_region);
1780        let mapped = self
1781            .dispatch_raw(child_raw, child_region, Permit::Copy)
1782            .map_err(|error| {
1783                with_error_context(error, &format!("field `{}`", field.name.as_str()))
1784            })?;
1785        if is_unchanged(&mapped) || same_shallow(child_raw, *mapped.as_raw_ffi_any()) {
1786            return Ok(());
1787        }
1788
1789        call_field_setter(field, source_address, mapped.as_raw_ffi_any()).map_err(|error| {
1790            with_error_context(error, &format!("field `{}`", field.name.as_str()))
1791        })?;
1792        *field_changed = true;
1793        Ok(())
1794    }
1795}
1796
1797type StructuralMutatorHandle = *mut RuntimeStructuralMutatorObj;
1798
1799type FStructuralMutate =
1800    unsafe extern "C" fn(StructuralMutatorHandle, AnyView<'static>) -> TVMFFIAny;
1801type FStructuralVarRemapGet =
1802    unsafe extern "C" fn(StructuralMutatorHandle, AnyView<'static>) -> TVMFFIAny;
1803type FStructuralVarRemapSet =
1804    unsafe extern "C" fn(StructuralMutatorHandle, AnyView<'static>, AnyView<'static>) -> TVMFFIAny;
1805
1806/// Rust mirror of the C++ `StructuralMutatorVTable` ABI.
1807#[repr(C)]
1808struct StructuralMutatorVTable {
1809    mutate: FStructuralMutate,
1810    maybe_inplace_mutate: FStructuralMutate,
1811    var_remap_get: FStructuralVarRemapGet,
1812    var_remap_set: FStructuralVarRemapSet,
1813}
1814
1815type RuntimeDispatchMutateCallback =
1816    unsafe fn(*mut c_void, TVMFFIAny, DefRegionKind, Permit) -> Result<Any>;
1817type RuntimeVarRemapGetCallback = unsafe fn(*mut c_void, TVMFFIAny) -> Result<Option<Any>>;
1818type RuntimeVarRemapSetCallback = unsafe fn(*mut c_void, TVMFFIAny, &Any) -> Result<()>;
1819
1820struct RuntimeMutatorCallbacks {
1821    dispatch_mutate: RuntimeDispatchMutateCallback,
1822    var_remap_get: RuntimeVarRemapGetCallback,
1823    var_remap_set: RuntimeVarRemapSetCallback,
1824}
1825
1826/// Active Rust mutator with the exact C++ `StructuralMutatorObj` prefix.
1827///
1828/// C++ type hooks read `vtable` and `def_region_mode`; Rust keeps its erased
1829/// driver state after that shared prefix.
1830#[repr(C)]
1831struct RuntimeStructuralMutatorObj {
1832    base: Object,
1833    vtable: *const StructuralMutatorVTable,
1834    def_region_mode: i32,
1835    // `context` is available only while a registered type hook is allowed to
1836    // re-enter Rust. `context_identity` is never dereferenced; it verifies
1837    // that a helper is being called on the mutator that started this run.
1838    context: *mut c_void,
1839    context_identity: *mut c_void,
1840    owner_thread: std::thread::ThreadId,
1841    callbacks: RuntimeMutatorCallbacks,
1842    // Identity substitutions for the active traversal.
1843    remap: RefCell<StructuralVarRemap>,
1844    panic: Option<Box<dyn std::any::Any + Send>>,
1845}
1846
1847const _: () = {
1848    assert!(
1849        std::mem::offset_of!(RuntimeStructuralMutatorObj, vtable)
1850            == std::mem::size_of::<TVMFFIObject>()
1851    );
1852    assert!(
1853        std::mem::offset_of!(RuntimeStructuralMutatorObj, def_region_mode)
1854            == std::mem::size_of::<TVMFFIObject>() + std::mem::size_of::<*const c_void>()
1855    );
1856};
1857
1858// SAFETY: `RuntimeStructuralMutatorObj` is `repr(C)` and starts with `Object`,
1859// so `object_header_mut` returns the allocation's actual TVMFFIObject header.
1860// `type_index` resolves the registered `ffi.StructuralMutator` subtype whose
1861// C++ prefix is checked by the compile-time offset assertions above.
1862unsafe impl ObjectCore for RuntimeStructuralMutatorObj {
1863    const TYPE_KEY: &'static str = "ffi.StructuralMutator";
1864    const TYPE_DEPTH: i32 = Object::TYPE_DEPTH + 1;
1865
1866    fn type_index() -> i32 {
1867        static TYPE_INDEX: LazyLock<i32> = LazyLock::new(|| unsafe {
1868            let key = TVMFFIByteArray::from_str(RuntimeStructuralMutatorObj::TYPE_KEY);
1869            let mut type_index = 0;
1870            let return_code = TVMFFITypeKeyToIndex(&key, &mut type_index);
1871            if return_code != 0 {
1872                panic!(
1873                    "ffi.StructuralMutator is not registered: {}",
1874                    Error::from_raised()
1875                );
1876            }
1877            type_index
1878        });
1879        *TYPE_INDEX
1880    }
1881
1882    unsafe fn object_header_mut(this: &mut Self) -> &mut TVMFFIObject {
1883        Object::object_header_mut(&mut this.base)
1884    }
1885}
1886
1887static RUST_STRUCTURAL_MUTATOR_VTABLE: StructuralMutatorVTable = StructuralMutatorVTable {
1888    mutate: rust_vtable_mutate,
1889    maybe_inplace_mutate: rust_vtable_maybe_inplace_mutate,
1890    var_remap_get: rust_vtable_var_remap_get,
1891    var_remap_set: rust_vtable_var_remap_set,
1892};
1893
1894struct RuntimeContextGuard {
1895    mutator: StructuralMutatorHandle,
1896    context: *mut c_void,
1897}
1898
1899impl Drop for RuntimeContextGuard {
1900    fn drop(&mut self) {
1901        // SAFETY: the guard is created only for a live mutator on its owner
1902        // thread. Restoring the pointer makes the same registered hook able to
1903        // invoke another child after this callback returns.
1904        unsafe { (*self.mutator).context = self.context };
1905    }
1906}
1907
1908/// Temporarily take the erased driver context out of the runtime object.
1909///
1910/// # Safety
1911///
1912/// `mutator` must be null or point to a live [`RuntimeStructuralMutatorObj`].
1913/// A non-null context must have been installed by the current run. Its runtime
1914/// callback table must reconstruct it according to that run's mutable-driver
1915/// contract.
1916unsafe fn take_runtime_context(mutator: StructuralMutatorHandle) -> Result<RuntimeContextGuard> {
1917    if !is_active_mutator(mutator) {
1918        return Err(inactive_mutator_error(mutator, "callback"));
1919    }
1920    let context = (*mutator).context;
1921    if context.is_null() {
1922        let message = if (*mutator).context_identity.is_null() {
1923            "structural mutator was retained after its active call"
1924        } else {
1925            "structural mutator may only be called by its active registered hook"
1926        };
1927        return Err(runtime_error(message));
1928    }
1929    // No raw context pointer remains callable while Rust executes the selected
1930    // mutable-driver entry.
1931    (*mutator).context = std::ptr::null_mut();
1932    Ok(RuntimeContextGuard { mutator, context })
1933}
1934
1935unsafe extern "C" fn rust_vtable_mutate(
1936    mutator: StructuralMutatorHandle,
1937    value: AnyView<'static>,
1938) -> TVMFFIAny {
1939    // SAFETY: this function is installed only in the vtable of a live
1940    // RuntimeStructuralMutatorObj; `value` is borrowed for this call.
1941    rust_vtable_mutate_impl(mutator, value, Permit::Copy)
1942}
1943
1944unsafe extern "C" fn rust_vtable_maybe_inplace_mutate(
1945    mutator: StructuralMutatorHandle,
1946    value: AnyView<'static>,
1947) -> TVMFFIAny {
1948    // SAFETY: same vtable and borrowed-value contract as
1949    // `rust_vtable_mutate`.
1950    rust_vtable_mutate_impl(mutator, value, Permit::MaybeInPlace)
1951}
1952
1953/// Run one erased vtable mutation callback and convert its result to ABI form.
1954///
1955/// # Safety
1956///
1957/// `mutator` must be a live runtime mutator handle, and `value` must remain
1958/// valid for this call.
1959unsafe fn rust_vtable_mutate_impl(
1960    mutator: StructuralMutatorHandle,
1961    value: AnyView<'static>,
1962    permit: Permit,
1963) -> TVMFFIAny {
1964    let context_guard = match take_runtime_context(mutator) {
1965        Ok(guard) => guard,
1966        Err(error) => return result_into_raw(Err(error)),
1967    };
1968    let context = context_guard.context;
1969    let callback = (*mutator).callbacks.dispatch_mutate;
1970    let raw = *value.as_raw_ffi_any();
1971    let outcome = catch_unwind(AssertUnwindSafe(|| {
1972        let kind = def_region_from_raw((*mutator).def_region_mode)?;
1973        with_active_mutator(mutator, || callback(context, raw, kind, permit))
1974    }));
1975    match outcome {
1976        Ok(result) => result_into_raw(result),
1977        Err(payload) => {
1978            (*mutator).panic = Some(payload);
1979            result_into_raw(Err(runtime_error("panic in structural mutator callback")))
1980        }
1981    }
1982}
1983
1984unsafe extern "C" fn rust_vtable_var_remap_get(
1985    mutator: StructuralMutatorHandle,
1986    var: AnyView<'static>,
1987) -> TVMFFIAny {
1988    let context_guard = match take_runtime_context(mutator) {
1989        Ok(guard) => guard,
1990        Err(error) => return result_into_raw(Err(error)),
1991    };
1992    let callback = (*mutator).callbacks.var_remap_get;
1993    let context = context_guard.context;
1994    let raw = *var.as_raw_ffi_any();
1995    match catch_unwind(AssertUnwindSafe(|| callback(context, raw))) {
1996        Ok(Ok(Some(replacement))) => Any::into_raw_ffi_any(replacement),
1997        Ok(Ok(None)) => TVMFFIAny::new(),
1998        Ok(Err(error)) => result_into_raw(Err(error)),
1999        Err(payload) => {
2000            (*mutator).panic = Some(payload);
2001            result_into_raw(Err(runtime_error("panic in structural var-remap lookup")))
2002        }
2003    }
2004}
2005
2006unsafe extern "C" fn rust_vtable_var_remap_set(
2007    mutator: StructuralMutatorHandle,
2008    var: AnyView<'static>,
2009    replacement: AnyView<'static>,
2010) -> TVMFFIAny {
2011    let context_guard = match take_runtime_context(mutator) {
2012        Ok(guard) => guard,
2013        Err(error) => return result_into_raw(Err(error)),
2014    };
2015    let callback = (*mutator).callbacks.var_remap_set;
2016    let context = context_guard.context;
2017    let var_raw = *var.as_raw_ffi_any();
2018    let replacement_raw = *replacement.as_raw_ffi_any();
2019    match catch_unwind(AssertUnwindSafe(|| {
2020        let replacement = owned_from_raw(replacement_raw)?;
2021        callback(context, var_raw, &replacement)
2022    })) {
2023        Ok(Ok(())) => TVMFFIAny::new(),
2024        Ok(Err(error)) => result_into_raw(Err(error)),
2025        Err(payload) => {
2026            (*mutator).panic = Some(payload);
2027            result_into_raw(Err(runtime_error(
2028                "panic in structural var-remap insertion",
2029            )))
2030        }
2031    }
2032}
2033
2034thread_local! {
2035    static ACTIVE_MUTATOR: Cell<StructuralMutatorHandle> = const {
2036        Cell::new(std::ptr::null_mut())
2037    };
2038}
2039
2040fn with_active_mutator<T>(handle: StructuralMutatorHandle, callback: impl FnOnce() -> T) -> T {
2041    ACTIVE_MUTATOR.with(|active| {
2042        let previous = active.replace(handle);
2043        struct Restore<'a> {
2044            active: &'a Cell<StructuralMutatorHandle>,
2045            previous: StructuralMutatorHandle,
2046        }
2047        impl Drop for Restore<'_> {
2048            fn drop(&mut self) {
2049                self.active.set(self.previous);
2050            }
2051        }
2052        let _restore = Restore { active, previous };
2053        callback()
2054    })
2055}
2056
2057fn active_mutator() -> Result<StructuralMutatorHandle> {
2058    ACTIVE_MUTATOR.with(|active| {
2059        let handle = active.get();
2060        if handle.is_null() {
2061            Err(runtime_error(
2062                "structural mutator helper called outside structural_mutate",
2063            ))
2064        } else {
2065            Ok(handle)
2066        }
2067    })
2068}
2069
2070fn invocation_var_remap_get<U: Sized>(mutator: &mut U, var: &MapValue) -> Result<Option<Any>> {
2071    let active = active_mutator()?;
2072    let context = std::ptr::from_mut(mutator).cast::<c_void>();
2073    unsafe {
2074        if (*active).context_identity != context {
2075            return Err(runtime_error(
2076                "default structural var-remap used by a non-active mutator",
2077            ));
2078        }
2079        (*active).remap.borrow().get(var)
2080    }
2081}
2082
2083fn invocation_var_remap_set<U: Sized>(
2084    mutator: &mut U,
2085    var: &MapValue,
2086    mutated_value: &Any,
2087) -> Result<()> {
2088    let active = active_mutator()?;
2089    let context = std::ptr::from_mut(mutator).cast::<c_void>();
2090    unsafe {
2091        if (*active).context_identity != context {
2092            return Err(runtime_error(
2093                "default structural var-remap used by a non-active mutator",
2094            ));
2095        }
2096        (*active).remap.borrow_mut().set(var, mutated_value)
2097    }
2098}
2099
2100#[inline]
2101fn is_active_mutator(handle: StructuralMutatorHandle) -> bool {
2102    !handle.is_null() && ACTIVE_MUTATOR.with(|active| active.get() == handle)
2103}
2104
2105#[cold]
2106fn inactive_mutator_error(mutator: StructuralMutatorHandle, operation: &str) -> Error {
2107    if mutator.is_null() {
2108        return runtime_error("null active structural mutator");
2109    }
2110    // The immutable owner id lets a foreign thread be rejected before reading
2111    // context fields that the owner thread may be updating.
2112    unsafe {
2113        if (*mutator).owner_thread != std::thread::current().id() {
2114            return runtime_error(&format!(
2115                "structural mutator {operation} invoked from a different thread"
2116            ));
2117        }
2118        if (*mutator).context_identity.is_null() {
2119            runtime_error("structural mutator was retained after its active call")
2120        } else {
2121            runtime_error(&format!(
2122                "structural mutator {operation} may only be used by its active registered hook"
2123            ))
2124        }
2125    }
2126}
2127
2128/// Expose the current mutable reborrow only for the duration of one registered
2129/// type hook. Nested vtable calls then reborrow from this pointer, and
2130/// [`take_runtime_context`] hides it again while Rust is executing.
2131fn with_current_driver_context<D, T>(
2132    mutator: StructuralMutatorHandle,
2133    driver: &mut D,
2134    callback: impl FnOnce() -> Result<T>,
2135) -> Result<T> {
2136    let context = std::ptr::from_mut(driver).cast::<c_void>();
2137    if !is_active_mutator(mutator) {
2138        return Err(inactive_mutator_error(mutator, "helper"));
2139    }
2140    unsafe {
2141        if (*mutator).context_identity != context {
2142            return Err(runtime_error(
2143                "structural mutator helper called on a non-active mutator",
2144            ));
2145        }
2146        if !(*mutator).context.is_null() {
2147            return Err(runtime_error(
2148                "structural mutator driver context is already exposed",
2149            ));
2150        }
2151
2152        (*mutator).context = context;
2153        struct HideContext {
2154            mutator: StructuralMutatorHandle,
2155        }
2156        impl Drop for HideContext {
2157            fn drop(&mut self) {
2158                // SAFETY: this scope owns the temporary exposure and runs on
2159                // the mutator's owner thread.
2160                unsafe { (*self.mutator).context = std::ptr::null_mut() };
2161            }
2162        }
2163        let _hide = HideContext { mutator };
2164        callback()
2165    }
2166}
2167
2168fn def_region_from_raw(kind: i32) -> Result<DefRegionKind> {
2169    match kind {
2170        x if x == DefRegionKind::None as i32 => Ok(DefRegionKind::None),
2171        x if x == DefRegionKind::Pattern as i32 => Ok(DefRegionKind::Pattern),
2172        x if x == DefRegionKind::Simple as i32 => Ok(DefRegionKind::Simple),
2173        _ => Err(runtime_error("invalid structural definition-region kind")),
2174    }
2175}
2176
2177impl<D: MapDispatch> MutationDriver for NativeMapper<D> {
2178    fn dispatch_raw(
2179        &mut self,
2180        raw: TVMFFIAny,
2181        def_region_kind: DefRegionKind,
2182        permit: Permit,
2183    ) -> Result<Any> {
2184        self.map_raw(raw, def_region_kind, permit)
2185    }
2186
2187    fn var_remap_get_raw(&mut self, raw: TVMFFIAny) -> Result<Option<Any>> {
2188        self.remap.get(&MapValue::from_raw(raw))
2189    }
2190
2191    fn var_remap_set_raw(&mut self, raw: TVMFFIAny, replacement: &Any) -> Result<()> {
2192        self.remap.set(&MapValue::from_raw(raw), replacement)
2193    }
2194}
2195
2196impl<U: StructuralMutator> MutationDriver for U {
2197    fn dispatch_raw(
2198        &mut self,
2199        raw: TVMFFIAny,
2200        def_region_kind: DefRegionKind,
2201        permit: Permit,
2202    ) -> Result<Any> {
2203        dispatch_user_raw(self, raw, def_region_kind, permit)
2204    }
2205
2206    fn var_remap_get_raw(&mut self, raw: TVMFFIAny) -> Result<Option<Any>> {
2207        self.var_remap_get(&MapValue::from_raw(raw))
2208    }
2209
2210    fn var_remap_set_raw(&mut self, raw: TVMFFIAny, replacement: &Any) -> Result<()> {
2211        self.var_remap_set(&MapValue::from_raw(raw), replacement)
2212    }
2213}
2214
2215/// Invoke the concrete Rust driver selected when the runtime mutator was built.
2216///
2217/// # Safety
2218///
2219/// `context` must come from the current mutable reborrow of a live `D`; the
2220/// runtime object hides that pointer until this call returns.
2221unsafe fn runtime_dispatch_mutate<D: MutationDriver>(
2222    context: *mut c_void,
2223    raw: TVMFFIAny,
2224    def_region_kind: DefRegionKind,
2225    permit: Permit,
2226) -> Result<Any> {
2227    (&mut *context.cast::<D>()).dispatch_raw(raw, def_region_kind, permit)
2228}
2229
2230/// Dispatch a variable-remap lookup through the erased driver context.
2231///
2232/// # Safety
2233///
2234/// `context` must satisfy the same requirements as [`runtime_dispatch_mutate`].
2235unsafe fn runtime_var_remap_get<D: MutationDriver>(
2236    context: *mut c_void,
2237    raw: TVMFFIAny,
2238) -> Result<Option<Any>> {
2239    (&mut *context.cast::<D>()).var_remap_get_raw(raw)
2240}
2241
2242/// Dispatch a variable-remap insertion through the erased driver context.
2243///
2244/// # Safety
2245///
2246/// `context` must satisfy the same requirements as [`runtime_dispatch_mutate`], and
2247/// `replacement` must remain alive for this call.
2248unsafe fn runtime_var_remap_set<D: MutationDriver>(
2249    context: *mut c_void,
2250    raw: TVMFFIAny,
2251    replacement: &Any,
2252) -> Result<()> {
2253    (&mut *context.cast::<D>()).var_remap_set_raw(raw, replacement)
2254}
2255
2256fn run_structural_mutator<D: MutationDriver>(root: Any, driver: &mut D) -> Result<Any> {
2257    let context = std::ptr::from_mut(driver).cast::<c_void>();
2258    let callbacks = RuntimeMutatorCallbacks {
2259        dispatch_mutate: runtime_dispatch_mutate::<D>,
2260        var_remap_get: runtime_var_remap_get::<D>,
2261        var_remap_set: runtime_var_remap_set::<D>,
2262    };
2263    run_structural_mutator_with_context(root, context, callbacks)
2264}
2265
2266fn run_structural_mutator_with_context(
2267    root: Any,
2268    context: *mut c_void,
2269    callbacks: RuntimeMutatorCallbacks,
2270) -> Result<Any> {
2271    let mut active = ObjectArc::new(RuntimeStructuralMutatorObj {
2272        base: Object::new(),
2273        vtable: &RUST_STRUCTURAL_MUTATOR_VTABLE,
2274        def_region_mode: DefRegionKind::None as i32,
2275        context,
2276        context_identity: context,
2277        owner_thread: std::thread::current().id(),
2278        callbacks,
2279        remap: RefCell::new(StructuralVarRemap::default()),
2280        panic: None,
2281    });
2282    let handle = unsafe { ObjectArc::as_raw_mut(&mut active) };
2283    let result = with_active_mutator(handle, || {
2284        call_mutator(
2285            handle,
2286            *root.as_raw_ffi_any(),
2287            DefRegionKind::None,
2288            Permit::MaybeInPlace,
2289        )
2290    });
2291    // A structural hook may only use the active mutator synchronously on this
2292    // thread. Make a retained reference fail instead of exposing a dangling
2293    // Rust state pointer. Release invocation-local identity owners here as
2294    // well: foreign code may retain the ABI object after the run ends.
2295    unsafe {
2296        (*handle).remap.get_mut().clear();
2297        (*handle).context = std::ptr::null_mut();
2298        (*handle).context_identity = std::ptr::null_mut();
2299    }
2300    let panic = unsafe { (*handle).panic.take() };
2301    if let Some(payload) = panic {
2302        drop(result);
2303        resume_unwind(payload);
2304    }
2305    result.map(|result| if is_unchanged(&result) { root } else { result })
2306}
2307
2308fn call_mutator(
2309    mutator: StructuralMutatorHandle,
2310    raw: TVMFFIAny,
2311    def_region_kind: DefRegionKind,
2312    permit: Permit,
2313) -> Result<Any> {
2314    if mutator.is_null() {
2315        return Err(runtime_error("no active structural mutator"));
2316    }
2317    let use_inplace = permit == Permit::MaybeInPlace && object_is_unique(raw);
2318    let callback = unsafe {
2319        if use_inplace {
2320            (*(*mutator).vtable).maybe_inplace_mutate
2321        } else {
2322            (*(*mutator).vtable).mutate
2323        }
2324    };
2325    with_mutator_def_region(mutator, def_region_kind, || unsafe {
2326        let view = AnyView::from_raw_ffi_any(raw);
2327        result_from_raw(callback(mutator, view))
2328    })
2329}
2330
2331fn call_registered_structural_mutate(
2332    mutator: StructuralMutatorHandle,
2333    raw: TVMFFIAny,
2334    def_region_kind: DefRegionKind,
2335    permit: Permit,
2336) -> Result<Option<Any>> {
2337    let use_inplace = permit == Permit::MaybeInPlace && object_is_unique(raw);
2338    if use_inplace {
2339        if let Some(attr) = structural_maybe_inplace_mutate_column()
2340            .and_then(|column| column.get_raw(raw.type_index))
2341        {
2342            if attr.type_index == TVMFFITypeIndex::kTVMFFIOpaquePtr as i32
2343                || attr.type_index == TVMFFITypeIndex::kTVMFFIFunction as i32
2344            {
2345                return call_structural_mutate_hook(mutator, raw, def_region_kind, attr).map(Some);
2346            }
2347        }
2348    }
2349
2350    let Some(attr) = structural_mutate_column().and_then(|column| column.get_raw(raw.type_index))
2351    else {
2352        return Ok(None);
2353    };
2354    if attr.type_index == TVMFFITypeIndex::kTVMFFINone as i32 {
2355        return Ok(None);
2356    }
2357    call_structural_mutate_hook(mutator, raw, def_region_kind, attr).map(Some)
2358}
2359
2360fn call_structural_mutate_hook(
2361    mutator: StructuralMutatorHandle,
2362    raw: TVMFFIAny,
2363    def_region_kind: DefRegionKind,
2364    attr: TVMFFIAny,
2365) -> Result<Any> {
2366    with_mutator_def_region(mutator, def_region_kind, || unsafe {
2367        match attr.type_index {
2368            x if x == TVMFFITypeIndex::kTVMFFIOpaquePtr as i32 => {
2369                let pointer = attr.data_union.v_ptr;
2370                if pointer.is_null() {
2371                    return Err(runtime_error("structural mutation hook is null"));
2372                }
2373                // SAFETY: the `__s_mutate__`/`__s_maybe_inplace_mutate__`
2374                // registration protocol defines an opaque-pointer attribute
2375                // as exactly an FStructuralMutate function pointer.
2376                let hook: FStructuralMutate = std::mem::transmute(pointer);
2377                let value = AnyView::from_raw_ffi_any(raw);
2378                result_from_raw(hook(mutator, value))
2379            }
2380            x if x == TVMFFITypeIndex::kTVMFFIFunction as i32 => {
2381                let function = Function::try_from(AnyView::from_raw_ffi_any(attr))?;
2382                let mutator_value = borrowed_mutator_view(mutator);
2383                let value = AnyView::from_raw_ffi_any(raw);
2384                function.call_packed(&[mutator_value, value])
2385            }
2386            _ => Err(Error::new(
2387                TYPE_ERROR,
2388                "__s_mutate__ must be an opaque function pointer or ffi.Function",
2389                "",
2390            )),
2391        }
2392    })
2393}
2394
2395/// Borrow a live runtime mutator as an object-valued ABI argument.
2396///
2397/// # Safety
2398///
2399/// `mutator` must point to a live object and outlive the returned view. The
2400/// view does not increment the object's reference count.
2401unsafe fn borrowed_mutator_view<'a>(mutator: StructuralMutatorHandle) -> AnyView<'a> {
2402    let object = mutator.cast::<TVMFFIObject>();
2403    let mut raw = TVMFFIAny::new();
2404    raw.type_index = (*object).type_index;
2405    raw.small_str_len = 0;
2406    raw.data_union.v_obj = object;
2407    AnyView::from_raw_ffi_any(raw)
2408}
2409
2410fn result_into_raw(result: Result<Any>) -> TVMFFIAny {
2411    unsafe {
2412        match result {
2413            Ok(value) => Any::into_raw_ffi_any(value),
2414            Err(error) => Any::into_raw_ffi_any(Any::from(error)),
2415        }
2416    }
2417}
2418
2419/// Resolve only at an owning-value API boundary; internal Any carriers and
2420/// native hooks keep the unchanged tag to avoid acquiring the original.
2421fn resolve_result(result: Any, original: TVMFFIAny) -> Result<Any> {
2422    if is_unchanged(&result) {
2423        owned_from_raw(original)
2424    } else {
2425        Ok(result)
2426    }
2427}
2428
2429/// Take ownership of one value returned by a structural-mutation ABI hook.
2430///
2431/// # Safety
2432///
2433/// `raw` must contain one owning TVMFFIAny result that has not already been
2434/// consumed. An Error object is converted into the Rust error channel.
2435unsafe fn result_from_raw(raw: TVMFFIAny) -> Result<Any> {
2436    let value = Any::from_raw_ffi_any(raw);
2437    if value.type_index() != TVMFFITypeIndex::kTVMFFIError as i32 {
2438        return Ok(value);
2439    }
2440    match Error::try_from(value) {
2441        Ok(error) | Err(error) => Err(error),
2442    }
2443}
2444
2445fn with_mutator_def_region<T>(
2446    mutator: StructuralMutatorHandle,
2447    kind: DefRegionKind,
2448    callback: impl FnOnce() -> T,
2449) -> T {
2450    unsafe {
2451        let previous = (*mutator).def_region_mode;
2452        // Precedence: a pattern region propagates; entering any kind inside it has no effect.
2453        if previous == DefRegionKind::Pattern as i32 {
2454            return callback();
2455        }
2456        (*mutator).def_region_mode = kind as i32;
2457        struct Restore {
2458            mutator: StructuralMutatorHandle,
2459            previous: i32,
2460        }
2461        impl Drop for Restore {
2462            fn drop(&mut self) {
2463                unsafe { (*self.mutator).def_region_mode = self.previous };
2464            }
2465        }
2466        let _restore = Restore { mutator, previous };
2467        callback()
2468    }
2469}
2470
2471#[inline(always)]
2472fn dispatch_user_raw<U: StructuralMutator>(
2473    mutator: &mut U,
2474    raw: TVMFFIAny,
2475    def_region_kind: DefRegionKind,
2476    permit: Permit,
2477) -> Result<Any> {
2478    let result = if permit == Permit::MaybeInPlace && object_is_unique(raw) {
2479        let mut scoped_raw = raw;
2480        mutator
2481            .dispatch_maybe_inplace_mutate(InplaceValue::from_raw(&mut scoped_raw), def_region_kind)
2482    } else {
2483        mutator.dispatch_mutate(&MapValue::from_raw(raw), def_region_kind)
2484    };
2485    result.map_err(|error| with_value_context(error, raw))
2486}
2487
2488fn user_default_mutate<U: StructuralMutator>(
2489    mutator: &mut U,
2490    raw: TVMFFIAny,
2491    def_region_kind: DefRegionKind,
2492    permit: Permit,
2493) -> Result<Any> {
2494    default_mutate_driver(mutator, raw, def_region_kind, permit)
2495}
2496
2497fn default_mutate_driver<D: MutationDriver>(
2498    driver: &mut D,
2499    raw: TVMFFIAny,
2500    def_region_kind: DefRegionKind,
2501    permit: Permit,
2502) -> Result<Any> {
2503    // Match C++ DefaultMutateExpected: a registered type hook owns any
2504    // identity-remap policy for that type. Automatic remapping applies only
2505    // to the reflected fallback below.
2506    if let Some(mutated) = driver.call_registered_hook(raw, def_region_kind, permit)? {
2507        return Ok(mutated);
2508    }
2509    if raw.type_index < TVMFFITypeIndex::kTVMFFIStaticObjectBegin as i32 {
2510        return owned_from_raw(raw);
2511    }
2512
2513    let kind = structural_hash_kind(raw)?;
2514    let is_free_var = kind == Some(TVMFFISEqHashKind::kTVMFFISEqHashKindFreeVar as i32);
2515    let is_dag_node = kind == Some(TVMFFISEqHashKind::kTVMFFISEqHashKindDAGNode as i32);
2516    if is_free_var || is_dag_node {
2517        if let Some(mutated) = driver.var_remap_get_raw(raw)? {
2518            // The ABI uses None for a miss; an Unchanged marker is a cached result.
2519            if mutated.type_index() != TVMFFITypeIndex::kTVMFFINone as i32 {
2520                return Ok(mutated);
2521            }
2522        }
2523    }
2524    // A variable use with no binding retains its identity without visiting fields.
2525    if is_free_var && def_region_kind == DefRegionKind::None {
2526        return Ok(Unchanged.into());
2527    }
2528
2529    let result = driver.map_reflected(raw, def_region_kind)?;
2530    if is_dag_node
2531        || (is_free_var && (def_region_kind == DefRegionKind::Pattern || !is_unchanged(&result)))
2532    {
2533        // Keep markers for DAG nodes and pattern definitions. An unchanged simple
2534        // definition needs no binding: subsequent uses retain the original on a miss.
2535        driver.var_remap_set_raw(raw, &result)?;
2536    }
2537    Ok(result)
2538}
2539
2540/// Mutate a structured value with a mutator or typed callback chain.
2541///
2542/// The root is consumed to establish the ownership boundary for optional
2543/// in-place mutation. A matching callback supplies the final value; unmatched
2544/// values use default mutation.
2545pub fn structural_mutate<R, M>(root: R, mutator: impl IntoMutator<M>) -> Result<Any>
2546where
2547    R: Into<Any>,
2548{
2549    mutator.mutate_root(root.into())
2550}
2551
2552/// Transform a structured value graph with ordered replacement callbacks.
2553///
2554/// The root is consumed. A uniquely owned built-in container may therefore be
2555/// reused in place, while passing `root.clone()` keeps the original shared and
2556/// selects copy-on-write behavior. Map and Dict keys are anchors and are not
2557/// mapped. Their registered structural hooks own container traversal.
2558///
2559/// Callbacks run at every occurrence. Default reflected descent handles FreeVar
2560/// and DAG-node remapping; registered hooks own their type's remapping policy.
2561/// Callback replacements are not automatically recorded as substitutions.
2562///
2563/// In-place changes completed before an error are not rolled back. Because
2564/// this function consumes `root`, an error does not return the partly mapped
2565/// root to the caller.
2566pub fn structural_map<R, M, H>(root: R, mapper: H, order: WalkOrder) -> Result<Any>
2567where
2568    R: Into<Any>,
2569    H: IntoMapper<M>,
2570{
2571    let root = root.into();
2572    let mut native = NativeMapper {
2573        dispatch: mapper.into_mapper(),
2574        order,
2575        remap: StructuralVarRemap::default(),
2576    };
2577    run_structural_mutator(root, &mut native)
2578}
2579
2580fn shallow_copy(raw: TVMFFIAny) -> Result<Any> {
2581    let Some(attr) = shallow_copy_column().and_then(|column| column.get_raw(raw.type_index)) else {
2582        return Err(Error::new(
2583            TYPE_ERROR,
2584            &format!(
2585                "type `{}` cannot use reflected structural mutation because it does not define `{SHALLOW_COPY_ATTR}`",
2586                type_key_of(raw.type_index)
2587            ),
2588            "",
2589        ));
2590    };
2591    if attr.type_index != TVMFFITypeIndex::kTVMFFIFunction as i32 {
2592        return Err(Error::new(
2593            TYPE_ERROR,
2594            &format!("{SHALLOW_COPY_ATTR} must be an ffi.Function"),
2595            "",
2596        ));
2597    }
2598    let function = Function::try_from(unsafe { AnyView::from_raw_ffi_any(attr) })?;
2599    // `raw` is borrowed from the active mutation call and remains valid for
2600    // this synchronous packed call. Avoid an unnecessary object refcount
2601    // increment/decrement just to pass another borrowed view.
2602    let source = unsafe { AnyView::from_raw_ffi_any(raw) };
2603    let result = function.call_packed(&[source])?;
2604    let result_raw = *result.as_raw_ffi_any();
2605    let result_pointer = unsafe { result_raw.data_union.v_obj };
2606    let source_pointer = unsafe { raw.data_union.v_obj };
2607    if result_raw.type_index != raw.type_index
2608        || result_pointer.is_null()
2609        || result_pointer == source_pointer
2610    {
2611        return Err(Error::new(
2612            TYPE_ERROR,
2613            "shallow copy callback must return a distinct object with the same type as its input",
2614            "",
2615        ));
2616    }
2617    Ok(result)
2618}
2619
2620fn call_field_setter(
2621    field: &TVMFFIFieldInfo,
2622    field_address: *mut c_void,
2623    value: &TVMFFIAny,
2624) -> Result<()> {
2625    if field.setter.is_null() {
2626        return Err(Error::new(
2627            TYPE_ERROR,
2628            &format!(
2629                "cannot structurally mutate field `{}` because it does not define a setter",
2630                field.name.as_str()
2631            ),
2632            "",
2633        ));
2634    }
2635    let return_code = unsafe {
2636        if field.flags & FLAG_SETTER_IS_FUNCTION == 0 {
2637            // SAFETY: reflection registration requires a non-Function setter
2638            // pointer to use the TVMFFIFieldSetter signature.
2639            let setter: TVMFFIFieldSetter = std::mem::transmute(field.setter);
2640            setter(field_address, value)
2641        } else {
2642            let mut args = [TVMFFIAny::new(), *value];
2643            args[0].type_index = TVMFFITypeIndex::kTVMFFIOpaquePtr as i32;
2644            args[0].data_union.v_ptr = field_address;
2645            // Own the result slot before entering foreign code so a partial
2646            // owning result is released on both success and failure.
2647            let mut result = Any::new();
2648            TVMFFIFunctionCall(
2649                field.setter as TVMFFIObjectHandle,
2650                args.as_ptr(),
2651                2,
2652                Any::as_data_ptr(&mut result),
2653            )
2654        }
2655    };
2656    if return_code == 0 {
2657        Ok(())
2658    } else {
2659        Err(Error::from_raised())
2660    }
2661}
2662
2663fn structural_hash_kind(raw: TVMFFIAny) -> Result<Option<i32>> {
2664    if raw.type_index < TVMFFITypeIndex::kTVMFFIStaticObjectBegin as i32 {
2665        return Ok(None);
2666    }
2667    let type_info = checked_type_info(raw.type_index)?;
2668    unsafe {
2669        if (*type_info).metadata.is_null() {
2670            Ok(None)
2671        } else {
2672            Ok(Some((*(*type_info).metadata).structural_eq_hash_kind))
2673        }
2674    }
2675}
2676
2677fn object_identity_key(raw: TVMFFIAny) -> Result<NonNull<TVMFFIObject>> {
2678    if raw.type_index < TVMFFITypeIndex::kTVMFFIStaticObjectBegin as i32 {
2679        return Err(Error::new(
2680            TYPE_ERROR,
2681            "variable-remap keys must be object-backed values",
2682            "",
2683        ));
2684    }
2685    let pointer = unsafe { raw.data_union.v_obj };
2686    NonNull::new(pointer)
2687        .ok_or_else(|| runtime_error("native structural map: identity object has a null pointer"))
2688}
2689
2690fn checked_type_info(type_index: i32) -> Result<*const crate::tvm_ffi_sys::TVMFFITypeInfo> {
2691    let info = unsafe { TVMFFIGetTypeInfo(type_index) };
2692    if info.is_null() {
2693        Err(runtime_error(&format!(
2694            "native structural map: unregistered type index {type_index}"
2695        )))
2696    } else {
2697        Ok(info)
2698    }
2699}
2700
2701#[inline]
2702fn object_is_unique(raw: TVMFFIAny) -> bool {
2703    if raw.type_index < TVMFFITypeIndex::kTVMFFIStaticObjectBegin as i32 {
2704        return false;
2705    }
2706    let pointer = unsafe { raw.data_union.v_obj };
2707    !pointer.is_null() && unsafe { object::unsafe_::strong_count(pointer) == 1 }
2708}
2709
2710fn owned_from_raw(raw: TVMFFIAny) -> Result<Any> {
2711    if let Some(owned) = try_to_owned_without_normalization(raw) {
2712        return Ok(owned);
2713    }
2714    if raw.type_index >= TVMFFITypeIndex::kTVMFFIStaticObjectBegin as i32 {
2715        return Err(runtime_error(
2716            "native structural map: object-backed value has a null pointer",
2717        ));
2718    }
2719
2720    // Raw string/bytes views and ObjectRValueRef require normalization (or a
2721    // move) rather than a bitwise copy; keep the generic C ABI conversion for
2722    // those uncommon representations.
2723    let mut owned = Any::new();
2724    let return_code = unsafe { TVMFFIAnyViewToOwnedAny(&raw, Any::as_data_ptr(&mut owned)) };
2725    if return_code == 0 {
2726        Ok(owned)
2727    } else {
2728        Err(Error::from_raised())
2729    }
2730}
2731
2732fn with_value_context(error: Error, raw: TVMFFIAny) -> Error {
2733    if raw.type_index < TVMFFITypeIndex::kTVMFFIStaticObjectBegin as i32 {
2734        error
2735    } else {
2736        with_error_context(error, &format!("object `{}`", type_key_of(raw.type_index)))
2737    }
2738}
2739
2740fn with_error_context(error: Error, frame: &str) -> Error {
2741    with_structural_error_context(error, "map", frame)
2742}
2743
2744fn runtime_error(message: &str) -> Error {
2745    Error::new(RUNTIME_ERROR, message, "")
2746}
2747
2748fn cached_column(cache: &'static AtomicUsize, name: &'static str) -> Option<TypeAttrColumn> {
2749    let cached = cache.load(Ordering::Relaxed);
2750    if cached != 0 {
2751        let pointer = cached as *mut TVMFFITypeAttrColumn;
2752        return Some(unsafe { TypeAttrColumn::from_non_null(NonNull::new_unchecked(pointer)) });
2753    }
2754    let column = type_attr_column(name)?;
2755    // TypeAttrColumn is a transparent NonNull wrapper shared with the
2756    // structural-visit module. Registry column addresses are immortal.
2757    cache.store(column.as_ptr() as usize, Ordering::Relaxed);
2758    Some(column)
2759}
2760
2761static STRUCTURAL_MUTATE_COLUMN: AtomicUsize = AtomicUsize::new(0);
2762static STRUCTURAL_MAYBE_INPLACE_MUTATE_COLUMN: AtomicUsize = AtomicUsize::new(0);
2763static SHALLOW_COPY_COLUMN: AtomicUsize = AtomicUsize::new(0);
2764
2765fn structural_mutate_column() -> Option<TypeAttrColumn> {
2766    cached_column(&STRUCTURAL_MUTATE_COLUMN, STRUCTURAL_MUTATE_ATTR)
2767}
2768
2769fn structural_maybe_inplace_mutate_column() -> Option<TypeAttrColumn> {
2770    cached_column(
2771        &STRUCTURAL_MAYBE_INPLACE_MUTATE_COLUMN,
2772        STRUCTURAL_MAYBE_INPLACE_MUTATE_ATTR,
2773    )
2774}
2775
2776fn shallow_copy_column() -> Option<TypeAttrColumn> {
2777    cached_column(&SHALLOW_COPY_COLUMN, SHALLOW_COPY_ATTR)
2778}