tvm_ffi/extra/
structural_common.rs1use crate::any::{Any, AnyView};
21use crate::error::Error;
22use crate::function::Function;
23use crate::object::{self, ObjectCore, ObjectRefCore};
24use crate::reflection::FieldGetter;
25use crate::tvm_ffi_sys::{
26 TVMFFIAny, TVMFFIByteArray, TVMFFIGetTypeInfo, TVMFFITypeIndex, TVMFFITypeKeyToIndex,
27};
28
29pub(crate) fn with_structural_error_context(error: Error, operation: &str, frame: &str) -> Error {
31 Error::with_appended_backtrace(error, &format!("[native structural {operation}] {frame}\n"))
32}
33
34#[cold]
35pub(crate) fn with_visit_error_context(error: Error, raw: TVMFFIAny) -> Error {
36 if raw.type_index < TVMFFITypeIndex::kTVMFFIStaticObjectBegin as i32 {
37 return error;
38 }
39 let context = (|| {
40 let mut context_type = 0;
41 unsafe {
42 crate::check_safe_call!(TVMFFITypeKeyToIndex(
43 &TVMFFIByteArray::from_str("ffi.VisitErrorContext"),
44 &mut context_type,
45 ))
46 .ok()?;
47 }
48 let node = StructuralView::from_raw(raw).cast::<object::ObjectRef>()?;
49 let mut previous = error.extra_context();
50 let mut nodes = Vec::new();
51 if let Some(prior) = previous.as_ref() {
52 if AnyView::from(prior).type_index() == context_type {
53 let object = &**object::ObjectRef::data(prior);
54 let records = FieldGetter::new(context_type, "reverse_visit_pattern")
55 .ok()?
56 .get_any(object)
57 .ok()?;
58 let size = Function::get_global("ffi.ListSize")
59 .ok()?
60 .call_tuple((records.clone(),))
61 .ok()?
62 .try_as::<i64>()?;
63 let get_item = Function::get_global("ffi.ListGetItem").ok()?;
64 if size > 0 {
65 let last = get_item
66 .call_tuple((records.clone(), size - 1))
67 .ok()?
68 .try_as::<object::ObjectRef>();
69 if last.is_some_and(|last| last.same_as(&node)) {
71 return None;
72 }
73 }
74 for i in 0..size {
75 nodes.push(get_item.call_tuple((records.clone(), i)).ok()?);
76 }
77 previous = FieldGetter::new(context_type, "prev_error_context")
78 .ok()?
79 .get::<_, Option<object::ObjectRef>>(object)
80 .ok()?;
81 }
82 }
83 nodes.push(Any::from(node));
84 let records = Function::get_global("ffi.List")
85 .ok()?
86 .call_packed(&nodes.iter().map(AnyView::from).collect::<Vec<_>>())
87 .ok()?;
88 Function::get_global("ffi.MakeObjectFromPackedArgs")
89 .ok()?
90 .call_tuple((
91 context_type,
92 crate::String::from("reverse_visit_pattern"),
93 records,
94 crate::String::from("prev_error_context"),
95 previous,
96 ))
97 .ok()?
98 .try_as::<object::ObjectRef>()
99 })();
100 match context {
102 Some(context) => Error::new_with_cause_and_extra_context(
103 error.kind(),
104 error.message(),
105 error.backtrace(),
106 error.cause_chain().as_ref(),
107 Some(&context),
108 ),
109 None => error,
110 }
111}
112
113macro_rules! impl_callback_chain_tuple_arities {
115 ($impl_chain:ident) => {
116 impl_callback_chain_tuple_arities!(
117 @prefixes $impl_chain;
118 [];
119 (F0, M0, 0),
120 (F1, M1, 1),
121 (F2, M2, 2),
122 (F3, M3, 3),
123 (F4, M4, 4),
124 (F5, M5, 5),
125 (F6, M6, 6),
126 (F7, M7, 7),
127 (F8, M8, 8),
128 (F9, M9, 9),
129 (F10, M10, 10),
130 (F11, M11, 11)
131 );
132 };
133 (@prefixes $impl_chain:ident; [$($prefix:tt)*];) => {};
134 (
135 @prefixes $impl_chain:ident;
136 [$($prefix:tt)*];
137 $next:tt $(, $rest:tt)*
138 ) => {
139 $impl_chain!($($prefix)* $next);
140 impl_callback_chain_tuple_arities!(
141 @prefixes $impl_chain;
142 [$($prefix)* $next,];
143 $($rest),*
144 );
145 };
146}
147
148pub(crate) use impl_callback_chain_tuple_arities;
149
150#[repr(transparent)]
157pub struct StructuralView(TVMFFIAny);
158
159impl<'a> From<&'a StructuralView> for AnyView<'a> {
160 #[inline]
161 fn from(value: &'a StructuralView) -> Self {
162 unsafe { AnyView::from_raw_ffi_any(value.raw()) }
164 }
165}
166
167impl StructuralView {
168 #[inline]
169 pub(crate) fn from_raw(raw: TVMFFIAny) -> Self {
170 Self(raw)
171 }
172
173 #[inline]
174 pub(crate) fn from_any(value: &Any) -> &Self {
175 unsafe { &*std::ptr::from_ref(value.as_raw_ffi_any()).cast::<Self>() }
178 }
179
180 #[inline]
181 pub(crate) fn raw(&self) -> TVMFFIAny {
182 self.0
183 }
184
185 #[inline]
187 pub fn to_owned(&self) -> Any {
188 if let Some(owned) = try_to_owned_without_normalization(self.0) {
189 return owned;
190 }
191 Any::from(unsafe { AnyView::from_raw_ffi_any(self.0) })
192 }
193
194 #[inline]
196 pub fn cast<R: crate::type_traits::AnyCompatible>(&self) -> Option<R> {
197 unsafe {
198 if R::check_any_strict(&self.0) {
199 Some(R::copy_from_any_view_after_check(&self.0))
200 } else {
201 None
202 }
203 }
204 }
205
206 #[inline]
208 pub fn type_index(&self) -> i32 {
209 self.0.type_index
210 }
211
212 #[inline]
214 pub fn as_node<N: ObjectCore>(&self) -> Option<&N> {
215 if self.0.type_index < TVMFFITypeIndex::kTVMFFIStaticObjectBegin as i32 {
216 return None;
217 }
218 let base_type_index = N::type_index();
219 if self.0.type_index != base_type_index {
220 if N::TYPE_FINAL {
224 return None;
225 }
226 if !is_instance_at_depth(self.0.type_index, base_type_index, N::TYPE_DEPTH) {
227 return None;
228 }
229 }
230 Some(unsafe { &*(self.0.data_union.v_obj as *const N) })
231 }
232}
233
234#[inline]
240pub(crate) fn try_to_owned_without_normalization(raw: TVMFFIAny) -> Option<Any> {
241 if is_plain_inline(raw.type_index) {
242 return Some(unsafe { Any::from_raw_ffi_any(raw) });
243 }
244 if raw.type_index >= TVMFFITypeIndex::kTVMFFIStaticObjectBegin as i32 {
245 let object = unsafe { raw.data_union.v_obj };
246 if object.is_null() {
247 return None;
248 }
249 unsafe { object::unsafe_::inc_ref(object) };
250 return Some(unsafe { Any::from_raw_ffi_any(raw) });
251 }
252 None
253}
254
255pub(crate) use crate::any::is_plain_inline;
256
257#[inline]
258pub(crate) fn same_shallow(lhs: TVMFFIAny, rhs: TVMFFIAny) -> bool {
259 lhs.type_index == rhs.type_index
260 && lhs.small_str_len == rhs.small_str_len
261 && unsafe { lhs.data_union.v_uint64 == rhs.data_union.v_uint64 }
262}
263
264#[inline]
267fn is_instance_at_depth(object_type_index: i32, base_type_index: i32, base_depth: i32) -> bool {
268 if object_type_index == base_type_index {
269 return true;
270 }
271 if object_type_index < base_type_index {
274 return false;
275 }
276 unsafe {
277 let info = TVMFFIGetTypeInfo(object_type_index);
278 if info.is_null() {
279 return false;
280 }
281 if (*info).type_depth <= base_depth {
282 return false;
283 }
284 let ancestors = (*info).type_acenstors;
285 if ancestors.is_null() {
286 return false;
287 }
288 let ancestor = *ancestors.offset(base_depth as isize);
289 !ancestor.is_null() && (*ancestor).type_index == base_type_index
290 }
291}