1use std::cell::Cell;
45use std::marker::PhantomData;
46use std::ops::ControlFlow;
47use std::os::raw::c_void;
48use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
49use std::ptr::NonNull;
50use std::rc::Rc;
51use std::sync::atomic::{AtomicUsize, Ordering};
52use std::sync::LazyLock;
53
54use crate::any::{Any, AnyView};
55use crate::error::{Error, Result, RUNTIME_ERROR, TYPE_ERROR};
56use crate::function::Function;
57use crate::object::{Object, ObjectArc, ObjectCore};
58use crate::reflection::TypeAttrColumn;
59use crate::tvm_ffi_sys::TVMFFIFieldFlagBitMask::{
60 kTVMFFIFieldFlagBitMaskSEqHashDefPattern, kTVMFFIFieldFlagBitMaskSEqHashDefSimple,
61 kTVMFFIFieldFlagBitMaskSEqHashIgnore,
62};
63use crate::tvm_ffi_sys::{
64 TVMFFIAny, TVMFFIByteArray, TVMFFIDefRegionKind, TVMFFIFieldInfo, TVMFFIGetTypeInfo,
65 TVMFFIObject, TVMFFISEqHashKind, TVMFFITypeAttrColumn, TVMFFITypeIndex, TVMFFITypeKeyToIndex,
66};
67
68use super::structural_common::{
69 impl_callback_chain_tuple_arities, with_structural_error_context, with_visit_error_context,
70};
71
72const STRUCTURAL_VISIT_ATTR: &str = "__s_visit__";
73const FLAG_SEQ_HASH_IGNORE: i64 = kTVMFFIFieldFlagBitMaskSEqHashIgnore as i64;
74const FLAG_SEQ_HASH_DEF_PATTERN: i64 = kTVMFFIFieldFlagBitMaskSEqHashDefPattern as i64;
75const FLAG_SEQ_HASH_DEF_SIMPLE: i64 = kTVMFFIFieldFlagBitMaskSEqHashDefSimple as i64;
76
77pub enum WalkResult {
79 Advance,
81 Skip,
83 Interrupt,
85 InterruptWith(Any),
87}
88
89impl WalkResult {
90 pub fn interrupt_with<T: Into<Any>>(payload: T) -> Self {
92 Self::InterruptWith(payload.into())
93 }
94}
95
96pub trait IntoWalkResult {
101 fn into_walk_result(self) -> Result<WalkResult>;
102}
103
104impl IntoWalkResult for WalkResult {
105 fn into_walk_result(self) -> Result<WalkResult> {
106 Ok(self)
107 }
108}
109
110impl IntoWalkResult for Result<WalkResult> {
111 fn into_walk_result(self) -> Result<WalkResult> {
112 self
113 }
114}
115
116#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
118pub enum WalkOrder {
119 #[default]
121 PreOrder,
122 PostOrder,
124}
125
126#[repr(i32)]
132#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
133pub enum DefRegionKind {
134 #[default]
136 None = 0,
137 Pattern = 1,
139 Simple = 2,
141}
142
143const _: () = {
144 assert!(DefRegionKind::None as i32 == TVMFFIDefRegionKind::kTVMFFIDefRegionKindNone as i32);
145 assert!(
146 DefRegionKind::Pattern as i32 == TVMFFIDefRegionKind::kTVMFFIDefRegionKindPattern as i32
147 );
148 assert!(DefRegionKind::Simple as i32 == TVMFFIDefRegionKind::kTVMFFIDefRegionKindSimple as i32);
149};
150
151pub struct VisitInterrupt {
158 pub value: Any,
160}
161
162impl VisitInterrupt {
163 pub fn with<T: Into<Any>>(payload: T) -> Self {
165 Self {
166 value: payload.into(),
167 }
168 }
169}
170
171#[doc(hidden)]
173pub trait IntoVisitResult {
174 fn into_visit_result(self) -> Result<Option<VisitInterrupt>>;
175}
176
177impl IntoVisitResult for () {
178 #[inline]
179 fn into_visit_result(self) -> Result<Option<VisitInterrupt>> {
180 Ok(None)
181 }
182}
183
184impl IntoVisitResult for Result<()> {
185 #[inline]
186 fn into_visit_result(self) -> Result<Option<VisitInterrupt>> {
187 self.map(|()| None)
188 }
189}
190
191impl IntoVisitResult for Option<VisitInterrupt> {
192 #[inline]
193 fn into_visit_result(self) -> Result<Option<VisitInterrupt>> {
194 Ok(self)
195 }
196}
197
198impl IntoVisitResult for Result<Option<VisitInterrupt>> {
199 #[inline]
200 fn into_visit_result(self) -> Result<Option<VisitInterrupt>> {
201 self
202 }
203}
204
205pub use super::StructuralView;
206
207enum NativeHalt {
208 Interrupt(Any),
209 Error(Error),
210}
211
212impl From<Error> for NativeHalt {
213 fn from(error: Error) -> Self {
214 NativeHalt::Error(error)
215 }
216}
217
218type NativeResult = std::result::Result<(), NativeHalt>;
219
220mod policy;
221pub use policy::{ContextPolicy, DefaultContextPolicy, WalkWithContextPolicy};
222
223pub struct VisitContext<'a, State> {
228 driver: &'a mut dyn VisitContextDriver<State>,
229 current: StructuralView,
230 def_region_kind: DefRegionKind,
231 _not_send_sync: PhantomData<Rc<()>>,
232}
233
234trait VisitContextDriver<State> {
235 fn state(&self) -> &State;
236 fn state_mut(&mut self) -> &mut State;
237 fn visit_raw(
238 &mut self,
239 raw: TVMFFIAny,
240 def_region_kind: DefRegionKind,
241 ) -> Result<Option<VisitInterrupt>>;
242 fn visit_children_raw(
243 &mut self,
244 raw: TVMFFIAny,
245 def_region_kind: DefRegionKind,
246 ) -> Result<Option<VisitInterrupt>>;
247}
248
249impl<State> VisitContext<'_, State> {
250 pub fn state(&self) -> &State {
252 self.driver.state()
253 }
254
255 pub fn state_mut(&mut self) -> &mut State {
257 self.driver.state_mut()
258 }
259
260 pub fn current(&self) -> &StructuralView {
262 &self.current
263 }
264
265 pub fn def_region_kind(&self) -> DefRegionKind {
267 self.def_region_kind
268 }
269
270 pub fn visit<T>(&mut self, child: &T) -> Result<Option<VisitInterrupt>>
272 where
273 for<'x> AnyView<'x>: From<&'x T>,
274 {
275 self.visit_with(child, self.def_region_kind)
276 }
277
278 pub fn visit_with<T>(
280 &mut self,
281 child: &T,
282 def_region_kind: DefRegionKind,
283 ) -> Result<Option<VisitInterrupt>>
284 where
285 for<'x> AnyView<'x>: From<&'x T>,
286 {
287 let raw = raw_of(AnyView::from(child));
288 if raw.type_index == TVMFFITypeIndex::kTVMFFINone as i32 {
289 return Ok(None);
290 }
291 self.driver.visit_raw(raw, def_region_kind)
292 }
293
294 pub fn visit_children(&mut self) -> Result<Option<VisitInterrupt>> {
298 self.default_visit_children_raw(self.current.raw(), self.def_region_kind)
299 }
300
301 pub fn default_visit_children<T>(
312 &mut self,
313 value: &T,
314 def_region_kind: DefRegionKind,
315 ) -> Result<Option<VisitInterrupt>>
316 where
317 for<'x> AnyView<'x>: From<&'x T>,
318 {
319 self.default_visit_children_raw(raw_of(AnyView::from(value)), def_region_kind)
320 }
321
322 fn default_visit_children_raw(
323 &mut self,
324 raw: TVMFFIAny,
325 def_region_kind: DefRegionKind,
326 ) -> Result<Option<VisitInterrupt>> {
327 if raw.type_index == TVMFFITypeIndex::kTVMFFINone as i32 {
328 return Ok(None);
329 }
330 let kind = if self.def_region_kind == DefRegionKind::Pattern {
331 DefRegionKind::Pattern
332 } else {
333 def_region_kind
334 };
335 let active = active_structural_visitor()?;
336 with_visitor_def_region(active, kind, || self.driver.visit_children_raw(raw, kind))
339 }
340}
341
342#[diagnostic::on_unimplemented(
347 message = "`{Self}` is not a supported `structural_visit` visitor",
348 note = "accepted visitors: `&mut V` where `V: StructuralVisitor`; an `Fn` callback over an FFI value type `T`, `&N` of an object node type, or `&StructuralView`, followed by `&mut VisitContext<'_, ()>`; or a tuple of up to 12 such callbacks (tuples may nest)",
349 note = "callback arguments need explicit type annotations; use `VisitCallbacks::new(state, callbacks)` for ordinary mutable callback state"
350)]
351pub trait IntoVisitor<Marker> {
352 #[doc(hidden)]
353 fn visit_root(self, root: TVMFFIAny) -> Result<Option<VisitInterrupt>>;
354}
355
356impl<V: StructuralVisitor> IntoVisitor<V> for &mut V {
357 fn visit_root(self, root: TVMFFIAny) -> Result<Option<VisitInterrupt>> {
358 finish(run_structural_visitor(
359 root,
360 self,
361 user_runtime_vtable::<V>(),
362 ))
363 }
364}
365
366pub trait VisitChainLink<State, Marker>: visit_sealed::SealedLink<State, Marker> {
368 #[doc(hidden)]
369 fn try_visit(
370 &self,
371 value: &StructuralView,
372 visitor: &mut VisitContext<'_, State>,
373 ) -> Option<Result<Option<VisitInterrupt>>>;
374}
375
376mod visit_sealed {
377 use super::{IntoVisitResult, ObjectCore, StructuralView, VisitContext};
378
379 pub trait SealedLink<State, Marker> {}
380
381 impl<F, State, T, O> SealedLink<State, super::ByVisitOwnedLink<T>> for F
382 where
383 F: for<'visitor, 'driver> Fn(T, &'visitor mut VisitContext<'driver, State>) -> O,
384 O: IntoVisitResult,
385 {
386 }
387
388 impl<F, State, N: ObjectCore, O> SealedLink<State, super::ByVisitNodeLink<N>> for F
389 where
390 F: for<'value, 'visitor, 'driver> Fn(
391 &'value N,
392 &'visitor mut VisitContext<'driver, State>,
393 ) -> O,
394 O: IntoVisitResult,
395 {
396 }
397
398 impl<F, State, O> SealedLink<State, super::ByVisitCatchAllLink> for F
399 where
400 F: for<'value, 'visitor, 'driver> Fn(
401 &'value StructuralView,
402 &'visitor mut VisitContext<'driver, State>,
403 ) -> O,
404 O: IntoVisitResult,
405 {
406 }
407}
408
409#[doc(hidden)]
410pub struct ByVisitOwnedLink<T>(PhantomData<T>);
411
412impl<F, State, T, O> VisitChainLink<State, ByVisitOwnedLink<T>> for F
413where
414 F: for<'visitor, 'driver> Fn(T, &'visitor mut VisitContext<'driver, State>) -> O,
415 T: crate::type_traits::AnyCompatible,
416 O: IntoVisitResult,
417{
418 fn try_visit(
419 &self,
420 value: &StructuralView,
421 visitor: &mut VisitContext<'_, State>,
422 ) -> Option<Result<Option<VisitInterrupt>>> {
423 value
424 .cast::<T>()
425 .map(|typed| self(typed, visitor).into_visit_result())
426 }
427}
428
429#[doc(hidden)]
430pub struct ByVisitNodeLink<N>(PhantomData<N>);
431
432impl<F, State, N, O> VisitChainLink<State, ByVisitNodeLink<N>> for F
433where
434 F: for<'value, 'visitor, 'driver> Fn(
435 &'value N,
436 &'visitor mut VisitContext<'driver, State>,
437 ) -> O,
438 N: ObjectCore,
439 O: IntoVisitResult,
440{
441 fn try_visit(
442 &self,
443 value: &StructuralView,
444 visitor: &mut VisitContext<'_, State>,
445 ) -> Option<Result<Option<VisitInterrupt>>> {
446 value
447 .as_node::<N>()
448 .map(|node| self(node, visitor).into_visit_result())
449 }
450}
451
452#[doc(hidden)]
453pub enum ByVisitCatchAllLink {}
454
455impl<F, State, O> VisitChainLink<State, ByVisitCatchAllLink> for F
456where
457 F: for<'value, 'visitor, 'driver> Fn(
458 &'value StructuralView,
459 &'visitor mut VisitContext<'driver, State>,
460 ) -> O,
461 O: IntoVisitResult,
462{
463 fn try_visit(
464 &self,
465 value: &StructuralView,
466 visitor: &mut VisitContext<'_, State>,
467 ) -> Option<Result<Option<VisitInterrupt>>> {
468 Some(self(value, visitor).into_visit_result())
469 }
470}
471
472#[doc(hidden)]
473pub struct ByVisitChainLink<Markers>(PhantomData<fn(Markers)>);
474
475macro_rules! impl_visit_chain_link {
476 ($(($F:ident, $M:ident, $idx:tt)),+) => {
477 impl<State, $($F, $M,)+>
478 visit_sealed::SealedLink<State, ByVisitChainLink<($($M,)+)>> for ($($F,)+)
479 where
480 $($F: VisitChainLink<State, $M>,)+
481 {
482 }
483
484 impl<State, $($F, $M,)+> VisitChainLink<State, ByVisitChainLink<($($M,)+)>>
485 for ($($F,)+)
486 where
487 $($F: VisitChainLink<State, $M>,)+
488 {
489 fn try_visit(
490 &self,
491 value: &StructuralView,
492 visitor: &mut VisitContext<'_, State>,
493 ) -> Option<Result<Option<VisitInterrupt>>> {
494 $(
495 if let Some(result) = self.$idx.try_visit(value, visitor) {
496 return Some(result);
497 }
498 )+
499 None
500 }
501 }
502 };
503}
504
505impl_callback_chain_tuple_arities!(impl_visit_chain_link);
506
507pub struct VisitCallbacks<State, Link, Marker, Policy = DefaultContextPolicy> {
509 policy: Option<Rc<Policy>>,
510 state: State,
511 callbacks: Rc<Link>,
512 _marker: PhantomData<fn(Marker)>,
513}
514
515impl<State, Link, Marker> VisitCallbacks<State, Link, Marker>
516where
517 Link: VisitChainLink<State, Marker>,
518{
519 pub fn new(state: State, callbacks: Link) -> Self {
521 Self {
522 state,
523 callbacks: Rc::new(callbacks),
524 policy: None,
525 _marker: PhantomData,
526 }
527 }
528}
529
530impl<State, Link, Marker, Policy> VisitCallbacks<State, Link, Marker, Policy> {
531 pub fn with_policy<P: ContextPolicy<State>>(
534 self,
535 policy: P,
536 ) -> VisitCallbacks<State, Link, Marker, P> {
537 VisitCallbacks {
538 state: self.state,
539 callbacks: self.callbacks,
540 policy: Some(Rc::new(policy)),
541 _marker: PhantomData,
542 }
543 }
544
545 pub fn state(&self) -> &State {
547 &self.state
548 }
549
550 pub fn state_mut(&mut self) -> &mut State {
552 &mut self.state
553 }
554
555 pub fn into_state(self) -> State {
557 self.state
558 }
559}
560
561struct DirectVisitCallbacks<'a, Link, Marker> {
562 state: (),
563 callbacks: &'a Link,
564 _marker: PhantomData<fn(Marker)>,
565}
566
567#[doc(hidden)]
568pub trait VisitCallbackState<State> {
569 fn callback_state(&self) -> &State;
570 fn callback_state_mut(&mut self) -> &mut State;
571}
572
573impl<State, Link, Marker, Policy> VisitCallbackState<State>
574 for VisitCallbacks<State, Link, Marker, Policy>
575{
576 fn callback_state(&self) -> &State {
577 &self.state
578 }
579
580 fn callback_state_mut(&mut self) -> &mut State {
581 &mut self.state
582 }
583}
584
585impl<Link, Marker> VisitCallbackState<()> for DirectVisitCallbacks<'_, Link, Marker> {
586 fn callback_state(&self) -> &() {
587 &self.state
588 }
589
590 fn callback_state_mut(&mut self) -> &mut () {
591 &mut self.state
592 }
593}
594
595#[doc(hidden)]
596pub struct ByVisitCallbacks<Marker>(PhantomData<fn(Marker)>);
597
598impl<Link, Marker> IntoVisitor<ByVisitCallbacks<Marker>> for Link
599where
600 Link: VisitChainLink<(), Marker>,
601{
602 fn visit_root(self, root: TVMFFIAny) -> Result<Option<VisitInterrupt>> {
603 let callbacks = self;
604 let mut visitor = DirectVisitCallbacks::<Link, Marker> {
605 state: (),
606 callbacks: &callbacks,
607 _marker: PhantomData,
608 };
609 finish(run_structural_visitor(
610 root,
611 &mut visitor,
612 user_runtime_vtable::<DirectVisitCallbacks<Link, Marker>>(),
613 ))
614 }
615}
616
617pub use super::dispatch::{ByWalkDispatch, DispatchWalker, WalkDispatch};
619
620#[diagnostic::on_unimplemented(
626 message = "`{Self}` is not a supported `structural_walk` walker",
627 note = "accepted walkers: `&mut V` where `V: WalkDispatch`; a closure over `&StructuralView`, \
628 an FFI value type `T`, or `&N` of an object node type (`N: ObjectCore`, e.g. \
629 `&Object`), optionally with a trailing `DefRegionKind` argument; or a tuple of \
630 up to 12 such links (tuples nest, so `(a, (b, c))` chains more); \
631 or a `WalkWithContextPolicy` passed by value or mutable reference",
632 note = "closure arguments need explicit type annotations; ObjectRef wrappers like `String` \
633 or `Array<T>` are FFI value types — take them by value, not by reference"
634)]
635pub trait IntoWalker<Marker> {
636 #[doc(hidden)]
637 type Walker: NativeVisit;
638 #[doc(hidden)]
639 fn into_walker(self) -> Self::Walker;
640}
641
642impl<F, O> IntoWalker<ByCatchAllLink> for F
643where
644 F: for<'a> FnMut(&'a StructuralView) -> O,
645 O: IntoWalkResult,
646{
647 type Walker = ChainWalker<F, ByCatchAllLink>;
648 fn into_walker(self) -> Self::Walker {
649 ChainWalker::new(self)
650 }
651}
652
653impl<F, O> IntoWalker<ByCatchAllKindLink> for F
654where
655 F: for<'a> FnMut(&'a StructuralView, DefRegionKind) -> O,
656 O: IntoWalkResult,
657{
658 type Walker = ChainWalker<F, ByCatchAllKindLink>;
659 fn into_walker(self) -> Self::Walker {
660 ChainWalker::new(self)
661 }
662}
663
664pub trait WalkChainLink<Marker>: sealed::SealedLink<Marker> {
670 #[doc(hidden)]
673 fn try_call(
674 &mut self,
675 value: &StructuralView,
676 def_region_kind: DefRegionKind,
677 ) -> Option<Result<WalkResult>>;
678}
679
680mod sealed {
681 use super::{DefRegionKind, IntoWalkResult, ObjectCore, StructuralView, WalkDispatch};
682
683 pub trait SealedLink<Marker> {}
684
685 impl<F, T, O> SealedLink<super::ByOwnedLink<T>> for F
686 where
687 F: FnMut(T) -> O,
688 O: IntoWalkResult,
689 {
690 }
691 impl<F, T, O> SealedLink<super::ByOwnedKindLink<T>> for F
692 where
693 F: FnMut(T, DefRegionKind) -> O,
694 O: IntoWalkResult,
695 {
696 }
697 impl<F, N: ObjectCore, O> SealedLink<super::ByNodeLink<N>> for F
698 where
699 F: for<'a> FnMut(&'a N) -> O,
700 O: IntoWalkResult,
701 {
702 }
703 impl<F, N: ObjectCore, O> SealedLink<super::ByNodeKindLink<N>> for F
704 where
705 F: for<'a> FnMut(&'a N, DefRegionKind) -> O,
706 O: IntoWalkResult,
707 {
708 }
709 impl<F, O> SealedLink<super::ByCatchAllLink> for F
710 where
711 F: for<'a> FnMut(&'a StructuralView) -> O,
712 O: IntoWalkResult,
713 {
714 }
715 impl<F, O> SealedLink<super::ByCatchAllKindLink> for F
716 where
717 F: for<'a> FnMut(&'a StructuralView, DefRegionKind) -> O,
718 O: IntoWalkResult,
719 {
720 }
721 impl<V: WalkDispatch> SealedLink<super::ByWalkDispatchLink> for &mut V {}
722}
723
724#[doc(hidden)]
725pub struct ByOwnedLink<T>(PhantomData<T>);
726
727impl<F, T, O> WalkChainLink<ByOwnedLink<T>> for F
728where
729 F: FnMut(T) -> O,
730 T: crate::type_traits::AnyCompatible,
731 O: IntoWalkResult,
732{
733 #[inline]
734 fn try_call(
735 &mut self,
736 value: &StructuralView,
737 _def_region_kind: DefRegionKind,
738 ) -> Option<Result<WalkResult>> {
739 value
740 .cast::<T>()
741 .map(|typed| self(typed).into_walk_result())
742 }
743}
744
745#[doc(hidden)]
746pub struct ByOwnedKindLink<T>(PhantomData<T>);
747
748impl<F, T, O> WalkChainLink<ByOwnedKindLink<T>> for F
749where
750 F: FnMut(T, DefRegionKind) -> O,
751 T: crate::type_traits::AnyCompatible,
752 O: IntoWalkResult,
753{
754 #[inline]
755 fn try_call(
756 &mut self,
757 value: &StructuralView,
758 def_region_kind: DefRegionKind,
759 ) -> Option<Result<WalkResult>> {
760 value
761 .cast::<T>()
762 .map(|typed| self(typed, def_region_kind).into_walk_result())
763 }
764}
765
766#[doc(hidden)]
767pub struct ByNodeLink<N>(PhantomData<N>);
768
769impl<F, N, O> WalkChainLink<ByNodeLink<N>> for F
770where
771 F: for<'a> FnMut(&'a N) -> O,
772 N: ObjectCore,
773 O: IntoWalkResult,
774{
775 #[inline]
776 fn try_call(
777 &mut self,
778 value: &StructuralView,
779 _def_region_kind: DefRegionKind,
780 ) -> Option<Result<WalkResult>> {
781 value
782 .as_node::<N>()
783 .map(|node| self(node).into_walk_result())
784 }
785}
786
787#[doc(hidden)]
788pub struct ByNodeKindLink<N>(PhantomData<N>);
789
790impl<F, N, O> WalkChainLink<ByNodeKindLink<N>> for F
791where
792 F: for<'a> FnMut(&'a N, DefRegionKind) -> O,
793 N: ObjectCore,
794 O: IntoWalkResult,
795{
796 #[inline]
797 fn try_call(
798 &mut self,
799 value: &StructuralView,
800 def_region_kind: DefRegionKind,
801 ) -> Option<Result<WalkResult>> {
802 value
803 .as_node::<N>()
804 .map(|node| self(node, def_region_kind).into_walk_result())
805 }
806}
807
808#[doc(hidden)]
809pub enum ByCatchAllLink {}
810
811impl<F, O> WalkChainLink<ByCatchAllLink> for F
812where
813 F: for<'a> FnMut(&'a StructuralView) -> O,
814 O: IntoWalkResult,
815{
816 #[inline]
817 fn try_call(
818 &mut self,
819 value: &StructuralView,
820 _def_region_kind: DefRegionKind,
821 ) -> Option<Result<WalkResult>> {
822 Some(self(value).into_walk_result())
823 }
824}
825
826#[doc(hidden)]
827pub enum ByCatchAllKindLink {}
828
829impl<F, O> WalkChainLink<ByCatchAllKindLink> for F
830where
831 F: for<'a> FnMut(&'a StructuralView, DefRegionKind) -> O,
832 O: IntoWalkResult,
833{
834 #[inline]
835 fn try_call(
836 &mut self,
837 value: &StructuralView,
838 def_region_kind: DefRegionKind,
839 ) -> Option<Result<WalkResult>> {
840 Some(self(value, def_region_kind).into_walk_result())
841 }
842}
843
844#[doc(hidden)]
845pub struct ByChainLink<Markers>(PhantomData<fn(Markers)>);
846
847#[doc(hidden)]
848pub enum ByWalkDispatchLink {}
849
850impl<V: WalkDispatch> WalkChainLink<ByWalkDispatchLink> for &mut V {
851 #[inline]
852 fn try_call(
853 &mut self,
854 value: &StructuralView,
855 def_region_kind: DefRegionKind,
856 ) -> Option<Result<WalkResult>> {
857 self.dispatch_walk(value, def_region_kind)
858 }
859}
860
861#[doc(hidden)]
863pub struct ChainWalker<Link, Marker> {
864 link: Link,
865 marker: PhantomData<fn(Marker)>,
866}
867
868impl<Link, Marker> ChainWalker<Link, Marker> {
869 #[inline]
870 fn new(link: Link) -> Self {
871 ChainWalker {
872 link,
873 marker: PhantomData,
874 }
875 }
876}
877
878impl<Link, Marker> NativeVisit for ChainWalker<Link, Marker>
879where
880 Link: WalkChainLink<Marker>,
881{
882 #[inline]
883 fn visit(
884 &mut self,
885 value: &StructuralView,
886 def_region_kind: DefRegionKind,
887 ) -> Result<WalkResult> {
888 self.link
889 .try_call(value, def_region_kind)
890 .unwrap_or_else(|| Ok(WalkResult::Advance))
891 }
892}
893
894macro_rules! impl_chain_link {
895 ($(($F:ident, $M:ident, $idx:tt)),+) => {
896 impl<$($F, $M,)+> sealed::SealedLink<ByChainLink<($($M,)+)>> for ($($F,)+)
897 where
898 $($F: WalkChainLink<$M>,)+
899 {
900 }
901
902 impl<$($F, $M,)+> WalkChainLink<ByChainLink<($($M,)+)>> for ($($F,)+)
903 where
904 $($F: WalkChainLink<$M>,)+
905 {
906 #[inline]
907 fn try_call(
908 &mut self,
909 value: &StructuralView,
910 def_region_kind: DefRegionKind,
911 ) -> Option<Result<WalkResult>> {
912 $(
913 if let Some(result) = self.$idx.try_call(value, def_region_kind) {
914 return Some(result);
915 }
916 )+
917 None
918 }
919 }
920
921 impl<$($F, $M,)+> IntoWalker<($($M,)+)> for ($($F,)+)
922 where
923 $($F: WalkChainLink<$M>,)+
924 {
925 type Walker = ChainWalker<($($F,)+), ByChainLink<($($M,)+)>>;
926 fn into_walker(self) -> Self::Walker {
927 ChainWalker::new(self)
928 }
929 }
930 };
931}
932
933impl_callback_chain_tuple_arities!(impl_chain_link);
934
935macro_rules! impl_bare_link_walker {
936 ($(($marker:ident, $($fn_args:ty),+)),+ $(,)?) => {
937 $(
938 impl<F, T, O> IntoWalker<$marker<T>> for F
939 where
940 F: FnMut($($fn_args),+) -> O,
941 Self: WalkChainLink<$marker<T>>,
942 O: IntoWalkResult,
943 {
944 type Walker = ChainWalker<F, $marker<T>>;
945 fn into_walker(self) -> Self::Walker {
946 ChainWalker::new(self)
947 }
948 }
949 )+
950 };
951}
952
953impl_bare_link_walker!(
954 (ByOwnedLink, T),
955 (ByOwnedKindLink, T, DefRegionKind),
956 (ByNodeLink, &T),
957 (ByNodeKindLink, &T, DefRegionKind),
958);
959
960pub trait StructuralVisitor: Sized {
966 fn visit(
968 &mut self,
969 value: &StructuralView,
970 def_region_kind: DefRegionKind,
971 ) -> Result<Option<VisitInterrupt>>;
972
973 #[inline]
975 fn visit_child<T>(
976 &mut self,
977 child: &T,
978 def_region_kind: DefRegionKind,
979 ) -> Result<Option<VisitInterrupt>>
980 where
981 for<'x> AnyView<'x>: From<&'x T>,
982 {
983 let raw = raw_of(AnyView::from(child));
984 if raw.type_index == TVMFFITypeIndex::kTVMFFINone as i32 {
985 return Ok(None);
986 }
987 let active = active_structural_visitor()?;
988 let context = std::ptr::from_mut(self).cast::<c_void>();
989 finish(with_current_visitor_context(active, context, || {
990 call_visitor(active, raw, def_region_kind)
991 }))
992 }
993
994 #[inline]
996 fn default_visit_children(
997 &mut self,
998 value: &StructuralView,
999 def_region_kind: DefRegionKind,
1000 ) -> Result<Option<VisitInterrupt>> {
1001 default_user_visit_children(self, value, def_region_kind)
1002 }
1003}
1004
1005fn default_user_visit_children<V: StructuralVisitor>(
1006 visitor: &mut V,
1007 value: &StructuralView,
1008 def_region_kind: DefRegionKind,
1009) -> Result<Option<VisitInterrupt>> {
1010 let raw = value.raw();
1011 let context = std::ptr::from_mut(&mut *visitor).cast::<c_void>();
1012 finish(
1013 visit_children_raw(raw, &mut UserChildren { visitor }, context, def_region_kind)
1014 .map_err(|halt| with_value_context(halt, raw)),
1015 )
1016}
1017
1018#[doc(hidden)]
1019pub fn default_visit_with_policy<V: StructuralVisitor + VisitCallbackState<V>>(
1020 visitor: &mut V,
1021 policy: &impl ContextPolicy<V>,
1022 value: &StructuralView,
1023 kind: DefRegionKind,
1024) -> Result<Option<VisitInterrupt>> {
1025 policy::visit_with_policy(&mut policy::VisitDescent { visitor }, policy, value, kind)
1026}
1027
1028fn try_visit_callbacks<State, Link, Marker>(
1029 driver: &mut impl VisitContextDriver<State>,
1030 callback_ptr: *const Link,
1031 value: &StructuralView,
1032 def_region_kind: DefRegionKind,
1033) -> Result<Option<VisitInterrupt>>
1034where
1035 Link: VisitChainLink<State, Marker>,
1036{
1037 let mut visitor = VisitContext {
1038 driver,
1039 current: StructuralView::from_raw(value.raw()),
1040 def_region_kind,
1041 _not_send_sync: PhantomData,
1042 };
1043 match unsafe { (&*callback_ptr).try_visit(value, &mut visitor) } {
1046 Some(outcome) => outcome,
1047 None => visitor.visit_children(),
1048 }
1049}
1050
1051impl<State, Link, Marker, Policy> StructuralVisitor for VisitCallbacks<State, Link, Marker, Policy>
1052where
1053 Link: VisitChainLink<State, Marker>,
1054 Policy: ContextPolicy<State>,
1055{
1056 fn visit(
1057 &mut self,
1058 value: &StructuralView,
1059 def_region_kind: DefRegionKind,
1060 ) -> Result<Option<VisitInterrupt>> {
1061 let callback_ptr = Rc::as_ptr(&self.callbacks);
1062 try_visit_callbacks::<State, Link, Marker>(self, callback_ptr, value, def_region_kind)
1063 }
1064
1065 fn default_visit_children(
1066 &mut self,
1067 value: &StructuralView,
1068 def_region_kind: DefRegionKind,
1069 ) -> Result<Option<VisitInterrupt>> {
1070 let Some(policy) = self.policy.as_ref().map(Rc::clone) else {
1071 return default_user_visit_children(self, value, def_region_kind);
1072 };
1073 policy::visit_with_policy(
1074 &mut policy::VisitDescent { visitor: self },
1075 &*policy,
1076 value,
1077 def_region_kind,
1078 )
1079 }
1080}
1081
1082impl<Link, Marker> StructuralVisitor for DirectVisitCallbacks<'_, Link, Marker>
1083where
1084 Link: VisitChainLink<(), Marker>,
1085{
1086 fn visit(
1087 &mut self,
1088 value: &StructuralView,
1089 def_region_kind: DefRegionKind,
1090 ) -> Result<Option<VisitInterrupt>> {
1091 let callback_ptr = std::ptr::from_ref(self.callbacks);
1092 try_visit_callbacks::<(), Link, Marker>(self, callback_ptr, value, def_region_kind)
1093 }
1094}
1095
1096impl<State, Driver> VisitContextDriver<State> for Driver
1097where
1098 Driver: StructuralVisitor + VisitCallbackState<State>,
1099{
1100 fn state(&self) -> &State {
1101 self.callback_state()
1102 }
1103
1104 fn state_mut(&mut self) -> &mut State {
1105 self.callback_state_mut()
1106 }
1107
1108 fn visit_raw(
1109 &mut self,
1110 raw: TVMFFIAny,
1111 def_region_kind: DefRegionKind,
1112 ) -> Result<Option<VisitInterrupt>> {
1113 if raw.type_index == TVMFFITypeIndex::kTVMFFINone as i32 {
1114 return Ok(None);
1115 }
1116 let active = active_structural_visitor()?;
1117 let context = std::ptr::from_mut(self).cast::<c_void>();
1118 finish(with_current_visitor_context(active, context, || {
1119 call_visitor(active, raw, def_region_kind)
1120 }))
1121 }
1122
1123 fn visit_children_raw(
1124 &mut self,
1125 raw: TVMFFIAny,
1126 def_region_kind: DefRegionKind,
1127 ) -> Result<Option<VisitInterrupt>> {
1128 <Self as StructuralVisitor>::default_visit_children(
1129 self,
1130 &StructuralView::from_raw(raw),
1131 def_region_kind,
1132 )
1133 }
1134}
1135
1136#[doc(hidden)]
1138pub trait NativeVisit: Sized {
1139 const CUSTOM_DESCENT: bool = false;
1140
1141 fn walk_root(&mut self, root: AnyView<'_>, order: WalkOrder) -> Result<Option<VisitInterrupt>> {
1142 let root = raw_of(root);
1143 finish(match order {
1144 WalkOrder::PreOrder => {
1145 run_structural_visitor(root, self, walk_runtime_vtable::<Self, true>())
1146 }
1147 WalkOrder::PostOrder => {
1148 run_structural_visitor(root, self, walk_runtime_vtable::<Self, false>())
1149 }
1150 })
1151 }
1152
1153 fn visit(
1154 &mut self,
1155 value: &StructuralView,
1156 def_region_kind: DefRegionKind,
1157 ) -> Result<WalkResult>;
1158
1159 fn default_visit_children<const PRE_ORDER: bool>(
1160 &mut self,
1161 value: &StructuralView,
1162 def_region_kind: DefRegionKind,
1163 ) -> Result<Option<VisitInterrupt>> {
1164 default_walk_children::<Self, PRE_ORDER>(self, value, def_region_kind)
1165 }
1166}
1167
1168impl<V: NativeVisit> NativeVisit for &mut V {
1169 const CUSTOM_DESCENT: bool = V::CUSTOM_DESCENT;
1170
1171 fn walk_root(&mut self, root: AnyView<'_>, order: WalkOrder) -> Result<Option<VisitInterrupt>> {
1172 (**self).walk_root(root, order)
1175 }
1176
1177 fn visit(
1178 &mut self,
1179 value: &StructuralView,
1180 def_region_kind: DefRegionKind,
1181 ) -> Result<WalkResult> {
1182 (**self).visit(value, def_region_kind)
1183 }
1184
1185 fn default_visit_children<const PRE_ORDER: bool>(
1186 &mut self,
1187 value: &StructuralView,
1188 def_region_kind: DefRegionKind,
1189 ) -> Result<Option<VisitInterrupt>> {
1190 (**self).default_visit_children::<PRE_ORDER>(value, def_region_kind)
1191 }
1192}
1193
1194fn default_walk_children<V: NativeVisit, const PRE_ORDER: bool>(
1195 visitor: &mut V,
1196 value: &StructuralView,
1197 def_region_kind: DefRegionKind,
1198) -> Result<Option<VisitInterrupt>> {
1199 let context = std::ptr::from_mut(&mut *visitor).cast::<c_void>();
1200 finish(visit_children_raw(
1201 value.raw(),
1202 &mut WalkChildren::<V, PRE_ORDER> { visitor },
1203 context,
1204 def_region_kind,
1205 ))
1206}
1207
1208trait ChildVisit {
1210 fn visit_child(
1211 &mut self,
1212 child: &StructuralView,
1213 def_region_kind: DefRegionKind,
1214 ) -> NativeResult;
1215}
1216
1217struct WalkChildren<'a, V, const PRE_ORDER: bool> {
1218 visitor: &'a mut V,
1219}
1220
1221impl<V: NativeVisit, const PRE_ORDER: bool> ChildVisit for WalkChildren<'_, V, PRE_ORDER> {
1222 #[inline(always)]
1223 fn visit_child(
1224 &mut self,
1225 child: &StructuralView,
1226 def_region_kind: DefRegionKind,
1227 ) -> NativeResult {
1228 visit_raw::<V, PRE_ORDER>(child.raw(), self.visitor, def_region_kind)
1229 }
1230}
1231
1232struct UserChildren<'a, V> {
1233 visitor: &'a mut V,
1234}
1235
1236impl<V: StructuralVisitor> ChildVisit for UserChildren<'_, V> {
1237 #[inline]
1238 fn visit_child(
1239 &mut self,
1240 child: &StructuralView,
1241 def_region_kind: DefRegionKind,
1242 ) -> NativeResult {
1243 if child.type_index() == TVMFFITypeIndex::kTVMFFINone as i32 {
1244 return Ok(());
1245 }
1246 match with_visit_region(def_region_kind, |kind| self.visitor.visit(child, kind)) {
1247 Ok(None) => Ok(()),
1248 Ok(Some(interrupt)) => Err(NativeHalt::Interrupt(interrupt.value)),
1249 Err(error) => Err(with_value_context(NativeHalt::Error(error), child.raw())),
1250 }
1251 }
1252}
1253
1254#[inline(always)]
1256fn visit_raw<V: NativeVisit, const PRE_ORDER: bool>(
1257 value: TVMFFIAny,
1258 visitor: &mut V,
1259 def_region_kind: DefRegionKind,
1260) -> NativeResult {
1261 if value.type_index == TVMFFITypeIndex::kTVMFFINone as i32 {
1262 return Ok(());
1263 }
1264 let visit_value = StructuralView::from_raw(value);
1265 if PRE_ORDER {
1266 let action = visitor
1267 .visit(&visit_value, def_region_kind)
1268 .map_err(|error| with_value_context(error.into(), value))?;
1269 match action {
1270 WalkResult::Advance => {}
1271 WalkResult::Skip => return Ok(()),
1272 WalkResult::Interrupt => return Err(NativeHalt::Interrupt(Any::new())),
1273 WalkResult::InterruptWith(payload) => return Err(NativeHalt::Interrupt(payload)),
1274 }
1275 }
1276
1277 if V::CUSTOM_DESCENT {
1278 match visitor.default_visit_children::<PRE_ORDER>(&visit_value, def_region_kind) {
1279 Ok(None) => {}
1280 Ok(Some(interrupt)) => return Err(NativeHalt::Interrupt(interrupt.value)),
1281 Err(error) => return Err(with_value_context(error.into(), value)),
1282 }
1283 } else if value.type_index >= TVMFFITypeIndex::kTVMFFIStaticObjectBegin as i32
1284 || has_registered_visit_hook(value.type_index)
1285 {
1286 let context = std::ptr::from_mut(&mut *visitor).cast::<c_void>();
1288 let children = &mut WalkChildren::<V, PRE_ORDER> { visitor };
1289 if let Err(halt) = visit_children_raw(value, children, context, def_region_kind) {
1290 return Err(with_value_context(halt, value));
1291 }
1292 }
1293
1294 if PRE_ORDER {
1295 Ok(())
1296 } else {
1297 match visitor.visit(&visit_value, def_region_kind) {
1298 Ok(WalkResult::Advance | WalkResult::Skip) => Ok(()),
1299 Ok(WalkResult::Interrupt) => Err(NativeHalt::Interrupt(Any::new())),
1300 Ok(WalkResult::InterruptWith(payload)) => Err(NativeHalt::Interrupt(payload)),
1301 Err(error) => Err(with_value_context(error.into(), value)),
1302 }
1303 }
1304}
1305
1306#[inline]
1307fn visit_children_raw<C: ChildVisit>(
1308 value: TVMFFIAny,
1309 visitor: &mut C,
1310 driver_context: *mut c_void,
1311 def_region_kind: DefRegionKind,
1312) -> NativeResult {
1313 if let Some(attr) =
1314 structural_visit_column().and_then(|column| column.get_raw(value.type_index))
1315 {
1316 if attr.type_index != TVMFFITypeIndex::kTVMFFINone as i32 {
1317 let active = active_structural_visitor()?;
1318 return with_current_visitor_context(active, driver_context, || {
1319 call_structural_visit_hook(active, value, def_region_kind, attr)
1320 });
1321 }
1322 }
1323
1324 if value.type_index < TVMFFITypeIndex::kTVMFFIStaticObjectBegin as i32 {
1325 Ok(())
1326 } else {
1327 visit_reflected_fields(value, visitor, def_region_kind)
1328 }
1329}
1330
1331#[inline]
1332fn visit_reflected_fields<C: ChildVisit>(
1333 value: TVMFFIAny,
1334 visitor: &mut C,
1335 def_region_kind: DefRegionKind,
1336) -> NativeResult {
1337 let type_info = unsafe { TVMFFIGetTypeInfo(value.type_index) };
1338 if type_info.is_null() {
1339 return Err(runtime_error(&format!(
1340 "native visitor: unregistered type index {}",
1341 value.type_index
1342 ))
1343 .into());
1344 }
1345 let seq_hash_kind = unsafe {
1346 let metadata = (*type_info).metadata;
1347 if metadata.is_null() {
1348 TVMFFISEqHashKind::kTVMFFISEqHashKindUnsupported as i32
1349 } else {
1350 (*metadata).structural_eq_hash_kind
1351 }
1352 };
1353 let def_region_kind = free_var_child_region(def_region_kind, seq_hash_kind);
1354 let object = unsafe { value.data_union.v_obj } as *mut u8;
1355 let halted = unsafe {
1356 for_each_field_info(type_info, &mut |field| match visit_reflected_field(
1357 object,
1358 field,
1359 visitor,
1360 def_region_kind,
1361 ) {
1362 Ok(()) => ControlFlow::Continue(()),
1363 Err(halt) => ControlFlow::Break(halt),
1364 })
1365 };
1366 halted.map_or(Ok(()), Err)
1367}
1368
1369unsafe fn visit_reflected_field<C: ChildVisit>(
1370 object: *mut u8,
1371 field: &TVMFFIFieldInfo,
1372 visitor: &mut C,
1373 inherited_region: DefRegionKind,
1374) -> NativeResult {
1375 if field.flags & FLAG_SEQ_HASH_IGNORE != 0 {
1376 return Ok(());
1377 }
1378
1379 let Some(getter) = field.getter else {
1380 return Err(NativeHalt::Error(runtime_error(&format!(
1381 "native visitor: reflected field `{}` has no getter",
1382 field.name.as_str()
1383 ))));
1384 };
1385 let address = object.offset(field.offset as isize) as *mut c_void;
1386 let mut child = Any::new();
1388 if getter(address, Any::as_data_ptr(&mut child)) != 0 {
1389 return Err(with_error_context(
1390 NativeHalt::Error(Error::from_raised()),
1391 &format!("field `{}`", field.name.as_str()),
1392 ));
1393 }
1394
1395 let borrowed = StructuralView::from_any(&child);
1396 let child_region = field_def_region(field, inherited_region);
1397 visitor
1398 .visit_child(borrowed, child_region)
1399 .map_err(|halt| with_error_context(halt, &format!("field `{}`", field.name.as_str())))
1400}
1401
1402type StructuralVisitorHandle = *mut RuntimeStructuralVisitorObj;
1403type FStructuralVisit =
1404 unsafe extern "C" fn(StructuralVisitorHandle, AnyView<'static>) -> TVMFFIAny;
1405
1406#[repr(C)]
1408struct StructuralVisitorVTable {
1409 visit: FStructuralVisit,
1410}
1411
1412#[repr(C)]
1414struct RuntimeStructuralVisitorObj {
1415 base: Object,
1416 vtable: *const StructuralVisitorVTable,
1417 def_region_mode: i32,
1418 context_identity: *mut c_void,
1420 owner_thread: std::thread::ThreadId,
1421 panic: Option<Box<dyn std::any::Any + Send>>,
1422}
1423
1424#[repr(C)]
1426struct RuntimeVisitInterruptObj {
1427 base: Object,
1428 value: Any,
1429}
1430
1431const _: () = {
1432 assert!(
1433 std::mem::offset_of!(RuntimeStructuralVisitorObj, vtable)
1434 == std::mem::size_of::<TVMFFIObject>()
1435 );
1436 assert!(
1437 std::mem::offset_of!(RuntimeStructuralVisitorObj, def_region_mode)
1438 == std::mem::size_of::<TVMFFIObject>() + std::mem::size_of::<*const c_void>()
1439 );
1440 assert!(
1441 std::mem::offset_of!(RuntimeVisitInterruptObj, value)
1442 == std::mem::size_of::<TVMFFIObject>()
1443 );
1444};
1445
1446unsafe impl ObjectCore for RuntimeStructuralVisitorObj {
1449 const TYPE_KEY: &'static str = "ffi.StructuralVisitor";
1450 const TYPE_DEPTH: i32 = Object::TYPE_DEPTH + 1;
1451
1452 fn type_index() -> i32 {
1453 static TYPE_INDEX: LazyLock<i32> = LazyLock::new(|| unsafe {
1454 let key = TVMFFIByteArray::from_str(RuntimeStructuralVisitorObj::TYPE_KEY);
1455 let mut type_index = 0;
1456 let return_code = TVMFFITypeKeyToIndex(&key, &mut type_index);
1457 if return_code != 0 {
1458 panic!(
1459 "ffi.StructuralVisitor is not registered: {}",
1460 Error::from_raised()
1461 );
1462 }
1463 type_index
1464 });
1465 *TYPE_INDEX
1466 }
1467
1468 unsafe fn object_header_mut(this: &mut Self) -> &mut TVMFFIObject {
1469 Object::object_header_mut(&mut this.base)
1470 }
1471}
1472
1473unsafe impl ObjectCore for RuntimeVisitInterruptObj {
1476 const TYPE_KEY: &'static str = "ffi.VisitInterrupt";
1477 const TYPE_DEPTH: i32 = Object::TYPE_DEPTH + 1;
1478 const TYPE_FINAL: bool = true;
1479
1480 fn type_index() -> i32 {
1481 TVMFFITypeIndex::kTVMFFIVisitInterrupt as i32
1482 }
1483
1484 unsafe fn object_header_mut(this: &mut Self) -> &mut TVMFFIObject {
1485 Object::object_header_mut(&mut this.base)
1486 }
1487}
1488
1489fn walk_runtime_vtable<V: NativeVisit, const PRE_ORDER: bool>() -> &'static StructuralVisitorVTable
1491{
1492 &StructuralVisitorVTable {
1493 visit: rust_vtable_walk::<V, PRE_ORDER>,
1494 }
1495}
1496
1497fn user_runtime_vtable<V: StructuralVisitor>() -> &'static StructuralVisitorVTable {
1498 &StructuralVisitorVTable {
1499 visit: rust_vtable_user::<V>,
1500 }
1501}
1502
1503struct RuntimeContextGuard {
1504 active: *mut ActiveStructuralVisitor,
1505 context: *mut c_void,
1506}
1507
1508impl Drop for RuntimeContextGuard {
1509 fn drop(&mut self) {
1510 unsafe { (*self.active).context = self.context };
1513 }
1514}
1515
1516struct ActiveStructuralVisitor {
1518 visitor: StructuralVisitorHandle,
1519 context: *mut c_void,
1520 context_identity: *mut c_void,
1521}
1522
1523#[inline(always)]
1529unsafe fn take_runtime_context(visitor: StructuralVisitorHandle) -> Result<RuntimeContextGuard> {
1530 let active = active_structural_visitor_state(visitor)
1531 .ok_or_else(|| inactive_structural_visitor_error(visitor, "callback"))?;
1532 let context = (*active).context;
1533 if context.is_null() {
1534 return Err(runtime_error(
1535 "structural visitor may only be called by its active registered hook",
1536 ));
1537 }
1538 (*active).context = std::ptr::null_mut();
1539 Ok(RuntimeContextGuard { active, context })
1540}
1541
1542unsafe extern "C" fn rust_vtable_walk<V: NativeVisit, const PRE_ORDER: bool>(
1543 visitor: StructuralVisitorHandle,
1544 value: AnyView<'static>,
1545) -> TVMFFIAny {
1546 rust_vtable_visit_impl(visitor, value, |context, raw, kind| {
1547 runtime_walk::<V, PRE_ORDER>(context, raw, kind)
1548 })
1549}
1550
1551unsafe extern "C" fn rust_vtable_user<V: StructuralVisitor>(
1552 visitor: StructuralVisitorHandle,
1553 value: AnyView<'static>,
1554) -> TVMFFIAny {
1555 rust_vtable_visit_impl(visitor, value, |context, raw, kind| {
1556 runtime_user_visit::<V>(context, raw, kind)
1557 })
1558}
1559
1560#[inline(always)]
1561unsafe fn rust_vtable_visit_impl(
1562 visitor: StructuralVisitorHandle,
1563 value: AnyView<'static>,
1564 callback: impl FnOnce(*mut c_void, TVMFFIAny, DefRegionKind) -> NativeResult,
1565) -> TVMFFIAny {
1566 let context_guard = match take_runtime_context(visitor) {
1567 Ok(guard) => guard,
1568 Err(error) => return native_result_into_raw(Err(NativeHalt::Error(error))),
1569 };
1570 let context = context_guard.context;
1571 let raw = *value.as_raw_ffi_any();
1572 let outcome = catch_unwind(AssertUnwindSafe(
1573 #[inline(always)]
1574 || {
1575 let result = def_region_from_raw((*visitor).def_region_mode)
1576 .map_err(NativeHalt::Error)
1577 .and_then(|kind| callback(context, raw, kind));
1578 native_result_into_raw(result)
1579 },
1580 ));
1581 match outcome {
1582 Ok(result) => result,
1583 Err(payload) => visit_panic_result(visitor, payload),
1584 }
1585}
1586
1587#[cold]
1588unsafe fn visit_panic_result(
1589 visitor: StructuralVisitorHandle,
1590 payload: Box<dyn std::any::Any + Send>,
1591) -> TVMFFIAny {
1592 (*visitor).panic = Some(payload);
1593 native_result_into_raw(Err(NativeHalt::Error(runtime_error(
1594 "panic in structural visitor callback",
1595 ))))
1596}
1597
1598thread_local! {
1599 static ACTIVE_STRUCTURAL_VISITOR: Cell<*mut ActiveStructuralVisitor> = const {
1600 Cell::new(std::ptr::null_mut())
1601 };
1602}
1603
1604fn with_active_structural_visitor<T>(
1605 active_state: &mut ActiveStructuralVisitor,
1606 callback: impl FnOnce() -> T,
1607) -> T {
1608 ACTIVE_STRUCTURAL_VISITOR.with(|active| {
1609 let previous = active.replace(std::ptr::from_mut(active_state));
1610 struct Restore<'a> {
1611 active: &'a Cell<*mut ActiveStructuralVisitor>,
1612 previous: *mut ActiveStructuralVisitor,
1613 }
1614 impl Drop for Restore<'_> {
1615 fn drop(&mut self) {
1616 self.active.set(self.previous);
1617 }
1618 }
1619 let _restore = Restore { active, previous };
1620 callback()
1621 })
1622}
1623
1624fn active_structural_visitor() -> Result<StructuralVisitorHandle> {
1625 ACTIVE_STRUCTURAL_VISITOR.with(|active| {
1626 let state = active.get();
1627 if state.is_null() {
1628 Err(runtime_error(
1629 "structural visitor helper called outside structural_visit or structural_walk",
1630 ))
1631 } else {
1632 Ok(unsafe { (*state).visitor })
1633 }
1634 })
1635}
1636
1637#[inline(always)]
1638fn active_structural_visitor_state(
1639 handle: StructuralVisitorHandle,
1640) -> Option<*mut ActiveStructuralVisitor> {
1641 ACTIVE_STRUCTURAL_VISITOR.with(|active| {
1642 let state = active.get();
1643 if state.is_null() || unsafe { (*state).visitor != handle } {
1644 None
1645 } else {
1646 Some(state)
1647 }
1648 })
1649}
1650
1651#[cold]
1652fn inactive_structural_visitor_error(visitor: StructuralVisitorHandle, operation: &str) -> Error {
1653 if visitor.is_null() {
1654 return runtime_error("null active structural visitor");
1655 }
1656 unsafe {
1660 if (*visitor).owner_thread != std::thread::current().id() {
1661 return runtime_error(&format!(
1662 "structural visitor {operation} invoked from a different thread"
1663 ));
1664 }
1665 if (*visitor).context_identity.is_null() {
1666 runtime_error("structural visitor was retained after its active call")
1667 } else {
1668 runtime_error(&format!(
1669 "structural visitor {operation} may only be used by its active registered hook"
1670 ))
1671 }
1672 }
1673}
1674
1675fn with_current_visitor_context(
1678 visitor: StructuralVisitorHandle,
1679 context: *mut c_void,
1680 callback: impl FnOnce() -> NativeResult,
1681) -> NativeResult {
1682 let active = checked_visitor_context(visitor, context)?;
1683 unsafe {
1684 (*active).context = context;
1685 struct HideContext {
1686 active: *mut ActiveStructuralVisitor,
1687 }
1688 impl Drop for HideContext {
1689 fn drop(&mut self) {
1690 unsafe { (*self.active).context = std::ptr::null_mut() };
1691 }
1692 }
1693 let _hide = HideContext { active };
1694 callback()
1695 }
1696}
1697
1698fn checked_visitor_context(
1699 visitor: StructuralVisitorHandle,
1700 context: *mut c_void,
1701) -> Result<*mut ActiveStructuralVisitor> {
1702 let active = active_structural_visitor_state(visitor)
1703 .ok_or_else(|| inactive_structural_visitor_error(visitor, "helper"))?;
1704 unsafe {
1705 if (*active).context_identity != context {
1706 return Err(runtime_error(
1707 "structural visitor helper called on a non-active visitor",
1708 ));
1709 }
1710 if !(*active).context.is_null() {
1711 return Err(runtime_error(
1712 "structural visitor context is already exposed",
1713 ));
1714 }
1715 Ok(active)
1716 }
1717}
1718
1719#[inline(always)]
1720unsafe fn runtime_walk<V: NativeVisit, const PRE_ORDER: bool>(
1721 context: *mut c_void,
1722 raw: TVMFFIAny,
1723 def_region_kind: DefRegionKind,
1724) -> NativeResult {
1725 visit_raw::<V, PRE_ORDER>(raw, &mut *context.cast::<V>(), def_region_kind)
1726}
1727
1728#[inline(always)]
1729unsafe fn runtime_user_visit<V: StructuralVisitor>(
1730 context: *mut c_void,
1731 raw: TVMFFIAny,
1732 def_region_kind: DefRegionKind,
1733) -> NativeResult {
1734 if raw.type_index == TVMFFITypeIndex::kTVMFFINone as i32 {
1735 return Ok(());
1736 }
1737 match (&mut *context.cast::<V>()).visit(&StructuralView::from_raw(raw), def_region_kind) {
1738 Ok(None) => Ok(()),
1739 Ok(Some(interrupt)) => Err(NativeHalt::Interrupt(interrupt.value)),
1740 Err(error) => Err(with_value_context(NativeHalt::Error(error), raw)),
1741 }
1742}
1743
1744fn run_structural_visitor<D>(
1745 root: TVMFFIAny,
1746 driver: &mut D,
1747 vtable: &'static StructuralVisitorVTable,
1748) -> NativeResult {
1749 let context = std::ptr::from_mut(driver).cast::<c_void>();
1750 let mut active = ObjectArc::new(RuntimeStructuralVisitorObj {
1751 base: Object::new(),
1752 vtable,
1753 def_region_mode: DefRegionKind::None as i32,
1754 context_identity: context,
1755 owner_thread: std::thread::current().id(),
1756 panic: None,
1757 });
1758 let handle = unsafe { ObjectArc::as_raw_mut(&mut active) };
1759 let mut active_state = ActiveStructuralVisitor {
1760 visitor: handle,
1761 context,
1762 context_identity: context,
1763 };
1764 let result = with_active_structural_visitor(&mut active_state, || {
1768 call_visitor(handle, root, DefRegionKind::None)
1769 });
1770 unsafe {
1771 (*handle).context_identity = std::ptr::null_mut();
1772 }
1773 let panic = unsafe { (*handle).panic.take() };
1774 if let Some(payload) = panic {
1775 drop(result);
1776 resume_unwind(payload);
1777 }
1778 result
1779}
1780
1781fn call_visitor(
1782 visitor: StructuralVisitorHandle,
1783 raw: TVMFFIAny,
1784 def_region_kind: DefRegionKind,
1785) -> NativeResult {
1786 if raw.type_index == TVMFFITypeIndex::kTVMFFINone as i32 {
1787 return Ok(());
1788 }
1789 if visitor.is_null() {
1790 return Err(runtime_error("no active structural visitor").into());
1791 }
1792 let callback = unsafe { (*(*visitor).vtable).visit };
1793 with_visitor_def_region(visitor, def_region_kind, || unsafe {
1794 let value = AnyView::from_raw_ffi_any(raw);
1795 visit_result_from_raw(callback(visitor, value))
1796 })
1797}
1798
1799fn call_structural_visit_hook(
1800 visitor: StructuralVisitorHandle,
1801 raw: TVMFFIAny,
1802 def_region_kind: DefRegionKind,
1803 attr: TVMFFIAny,
1804) -> NativeResult {
1805 with_visitor_def_region(visitor, def_region_kind, || unsafe {
1806 match attr.type_index {
1807 x if x == TVMFFITypeIndex::kTVMFFIOpaquePtr as i32 => {
1808 let pointer = attr.data_union.v_ptr;
1809 if pointer.is_null() {
1810 return Err(runtime_error("structural visit hook is null").into());
1811 }
1812 let hook: FStructuralVisit = std::mem::transmute(pointer);
1815 let value = AnyView::from_raw_ffi_any(raw);
1816 visit_result_from_raw(hook(visitor, value))
1817 }
1818 x if x == TVMFFITypeIndex::kTVMFFIFunction as i32 => {
1819 let function = Function::try_from(AnyView::from_raw_ffi_any(attr))?;
1820 let visitor_value = borrowed_visitor_view(visitor);
1821 let value = AnyView::from_raw_ffi_any(raw);
1822 visit_result_from_any(function.call_packed(&[visitor_value, value])?)
1823 }
1824 _ => Err(Error::new(
1825 TYPE_ERROR,
1826 "__s_visit__ must be an opaque function pointer or ffi.Function",
1827 "",
1828 )
1829 .into()),
1830 }
1831 })
1832}
1833
1834unsafe fn borrowed_visitor_view<'a>(visitor: StructuralVisitorHandle) -> AnyView<'a> {
1835 let object = visitor.cast::<TVMFFIObject>();
1836 let mut raw = TVMFFIAny::new();
1837 raw.type_index = (*object).type_index;
1838 raw.small_str_len = 0;
1839 raw.data_union.v_obj = object;
1840 AnyView::from_raw_ffi_any(raw)
1841}
1842
1843#[inline(always)]
1844fn native_result_into_raw(result: NativeResult) -> TVMFFIAny {
1845 match result {
1846 Ok(()) => TVMFFIAny::new(),
1847 Err(NativeHalt::Error(error)) => unsafe { Any::into_raw_ffi_any(Any::from(error)) },
1848 Err(NativeHalt::Interrupt(payload)) => {
1849 let interrupt = ObjectArc::new(RuntimeVisitInterruptObj {
1850 base: Object::new(),
1851 value: payload,
1852 });
1853 let object = unsafe { ObjectArc::into_raw(interrupt) }.cast_mut();
1854 let mut raw = TVMFFIAny::new();
1855 raw.type_index = TVMFFITypeIndex::kTVMFFIVisitInterrupt as i32;
1856 raw.data_union.v_obj = object.cast::<TVMFFIObject>();
1857 raw
1858 }
1859 }
1860}
1861
1862unsafe fn visit_result_from_raw(raw: TVMFFIAny) -> NativeResult {
1863 if raw.type_index == TVMFFITypeIndex::kTVMFFINone as i32 {
1866 Ok(())
1867 } else {
1868 visit_result_from_any(Any::from_raw_ffi_any(raw))
1869 }
1870}
1871
1872fn visit_result_from_any(value: Any) -> NativeResult {
1873 match value.type_index() {
1874 x if x == TVMFFITypeIndex::kTVMFFINone as i32 => Ok(()),
1875 x if x == TVMFFITypeIndex::kTVMFFIError as i32 => match Error::try_from(value) {
1876 Ok(error) | Err(error) => Err(NativeHalt::Error(error)),
1877 },
1878 x if x == TVMFFITypeIndex::kTVMFFIVisitInterrupt as i32 => {
1879 let raw = *value.as_raw_ffi_any();
1880 let object = unsafe { raw.data_union.v_obj };
1881 if object.is_null() {
1882 return Err(runtime_error("structural visit returned a null interrupt").into());
1883 }
1884 let payload = unsafe { (*object.cast::<RuntimeVisitInterruptObj>()).value.clone() };
1885 Err(NativeHalt::Interrupt(payload))
1886 }
1887 _ => Err(Error::new(
1888 TYPE_ERROR,
1889 "structural visit hook must return None or ffi.VisitInterrupt",
1890 "",
1891 )
1892 .into()),
1893 }
1894}
1895
1896#[inline(always)]
1897fn with_visit_region<T>(
1898 kind: DefRegionKind,
1899 callback: impl FnOnce(DefRegionKind) -> Result<T>,
1900) -> Result<T> {
1901 let active = active_structural_visitor()?;
1902 with_visitor_def_region(
1903 active,
1904 kind,
1905 #[inline(always)]
1906 || {
1907 let kind = def_region_from_raw(unsafe { (*active).def_region_mode })?;
1909 callback(kind)
1910 },
1911 )
1912}
1913
1914#[inline(always)]
1915fn with_visitor_def_region<T>(
1916 visitor: StructuralVisitorHandle,
1917 kind: DefRegionKind,
1918 callback: impl FnOnce() -> T,
1919) -> T {
1920 unsafe {
1921 let previous = (*visitor).def_region_mode;
1922 if previous != DefRegionKind::Pattern as i32 {
1924 (*visitor).def_region_mode = kind as i32;
1925 }
1926 struct Restore {
1927 visitor: StructuralVisitorHandle,
1928 previous: i32,
1929 }
1930 impl Drop for Restore {
1931 fn drop(&mut self) {
1932 if self.previous != DefRegionKind::Pattern as i32 {
1933 unsafe { (*self.visitor).def_region_mode = self.previous };
1934 }
1935 }
1936 }
1937 let _restore = Restore { visitor, previous };
1938 callback()
1939 }
1940}
1941
1942#[inline(always)]
1943fn def_region_from_raw(kind: i32) -> Result<DefRegionKind> {
1944 match kind {
1945 x if x == DefRegionKind::None as i32 => Ok(DefRegionKind::None),
1946 x if x == DefRegionKind::Pattern as i32 => Ok(DefRegionKind::Pattern),
1947 x if x == DefRegionKind::Simple as i32 => Ok(DefRegionKind::Simple),
1948 _ => Err(runtime_error("invalid structural definition-region kind")),
1949 }
1950}
1951
1952#[cold]
1953fn with_value_context(halt: NativeHalt, value: TVMFFIAny) -> NativeHalt {
1954 if value.type_index < TVMFFITypeIndex::kTVMFFIStaticObjectBegin as i32 {
1955 halt
1956 } else {
1957 let halt = match halt {
1958 NativeHalt::Error(error) => NativeHalt::Error(with_visit_error_context(error, value)),
1959 interrupt => interrupt,
1960 };
1961 with_error_context(halt, &format!("object `{}`", type_key_of(value.type_index)))
1962 }
1963}
1964
1965pub fn structural_visit<R, M>(
1970 root: &R,
1971 visitor: impl IntoVisitor<M>,
1972) -> Result<Option<VisitInterrupt>>
1973where
1974 for<'x> AnyView<'x>: From<&'x R>,
1975{
1976 visitor.visit_root(raw_of(AnyView::from(root)))
1977}
1978
1979pub fn structural_walk<R, M, H>(
1992 root: &R,
1993 walker: H,
1994 order: WalkOrder,
1995) -> Result<Option<VisitInterrupt>>
1996where
1997 H: IntoWalker<M>,
1998 for<'x> AnyView<'x>: From<&'x R>,
1999{
2000 walker.into_walker().walk_root(AnyView::from(root), order)
2001}
2002
2003fn finish(result: NativeResult) -> Result<Option<VisitInterrupt>> {
2004 match result {
2005 Ok(()) => Ok(None),
2006 Err(NativeHalt::Error(error)) => Err(error),
2007 Err(NativeHalt::Interrupt(payload)) => Ok(Some(VisitInterrupt { value: payload })),
2008 }
2009}
2010
2011#[inline]
2012pub(crate) fn field_def_region(field: &TVMFFIFieldInfo, inherited: DefRegionKind) -> DefRegionKind {
2013 if inherited == DefRegionKind::Pattern {
2015 DefRegionKind::Pattern
2016 } else if field.flags & FLAG_SEQ_HASH_DEF_SIMPLE != 0 {
2017 DefRegionKind::Simple
2018 } else if field.flags & FLAG_SEQ_HASH_DEF_PATTERN != 0 {
2019 DefRegionKind::Pattern
2020 } else {
2021 inherited
2022 }
2023}
2024
2025#[inline]
2030pub(crate) fn free_var_child_region(
2031 inherited: DefRegionKind,
2032 structural_eq_hash_kind: i32,
2033) -> DefRegionKind {
2034 if inherited == DefRegionKind::Simple
2035 && structural_eq_hash_kind == TVMFFISEqHashKind::kTVMFFISEqHashKindFreeVar as i32
2036 {
2037 DefRegionKind::None
2038 } else {
2039 inherited
2040 }
2041}
2042
2043#[cold]
2044fn with_error_context(halt: NativeHalt, frame: &str) -> NativeHalt {
2045 match halt {
2046 NativeHalt::Error(error) => {
2047 NativeHalt::Error(with_structural_error_context(error, "visit", frame))
2048 }
2049 interrupt => interrupt,
2050 }
2051}
2052
2053fn runtime_error(message: &str) -> Error {
2054 Error::new(RUNTIME_ERROR, message, "")
2055}
2056
2057pub(crate) fn type_attr_column(attr_name: &str) -> Option<TypeAttrColumn> {
2058 TypeAttrColumn::new(attr_name)
2059}
2060
2061static STRUCTURAL_VISIT_COLUMN: AtomicUsize = AtomicUsize::new(0);
2066
2067#[inline]
2068fn structural_visit_column() -> Option<TypeAttrColumn> {
2069 let cached = STRUCTURAL_VISIT_COLUMN.load(Ordering::Relaxed);
2070 if cached != 0 {
2071 let pointer = cached as *mut TVMFFITypeAttrColumn;
2072 return Some(unsafe { TypeAttrColumn::from_non_null(NonNull::new_unchecked(pointer)) });
2073 }
2074 initialize_structural_visit_column()
2075}
2076
2077#[inline]
2078fn has_registered_visit_hook(type_index: i32) -> bool {
2079 structural_visit_column()
2080 .and_then(|column| column.get_raw(type_index))
2081 .is_some_and(|attr| attr.type_index != TVMFFITypeIndex::kTVMFFINone as i32)
2082}
2083
2084#[cold]
2085#[inline(never)]
2086fn initialize_structural_visit_column() -> Option<TypeAttrColumn> {
2087 let column = type_attr_column(STRUCTURAL_VISIT_ATTR)?;
2088 STRUCTURAL_VISIT_COLUMN.store(column.as_ptr() as usize, Ordering::Relaxed);
2089 Some(column)
2090}
2091
2092pub(crate) fn type_key_of(type_index: i32) -> String {
2093 unsafe {
2094 let info = TVMFFIGetTypeInfo(type_index);
2095 if info.is_null() {
2096 format!("<type_index {type_index}>")
2097 } else {
2098 (*info).type_key.as_str().to_string()
2099 }
2100 }
2101}
2102
2103pub(crate) unsafe fn for_each_field_info<B>(
2110 info: *const crate::tvm_ffi_sys::TVMFFITypeInfo,
2111 callback: &mut impl FnMut(&'static TVMFFIFieldInfo) -> ControlFlow<B>,
2112) -> Option<B> {
2113 for depth in 1..(*info).type_depth {
2116 let ancestor = *(*info).type_acenstors.offset(depth as isize);
2117 if let Some(value) = visit_field_level(ancestor, callback) {
2118 return Some(value);
2119 }
2120 }
2121 visit_field_level(info, callback)
2122}
2123
2124unsafe fn visit_field_level<B>(
2125 info: *const crate::tvm_ffi_sys::TVMFFITypeInfo,
2126 callback: &mut impl FnMut(&'static TVMFFIFieldInfo) -> ControlFlow<B>,
2127) -> Option<B> {
2128 if info.is_null() || (*info).fields.is_null() {
2129 return None;
2130 }
2131 let fields = std::slice::from_raw_parts((*info).fields, (*info).num_fields as usize);
2132 for field in fields {
2133 let field: &'static TVMFFIFieldInfo = &*(field as *const TVMFFIFieldInfo);
2135 if let ControlFlow::Break(value) = callback(field) {
2136 return Some(value);
2137 }
2138 }
2139 None
2140}
2141
2142#[inline]
2143fn raw_of(view: AnyView<'_>) -> TVMFFIAny {
2144 *view.as_raw_ffi_any()
2145}