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