1use std::ffi::c_void;
23use std::ptr::NonNull;
24
25use crate::tvm_ffi_sys::{
26 TVMFFIAny, TVMFFIByteArray, TVMFFIFieldGetter, TVMFFIFieldInfo, TVMFFIGetTypeAttrColumn,
27 TVMFFIGetTypeInfo, TVMFFIObject, TVMFFITypeAttrColumn, TVMFFITypeIndex,
28};
29use crate::{Any, AnyView, Error, ObjectCore, Result, TYPE_ERROR};
30
31#[derive(Clone, Copy)]
36pub struct TypeAttrColumn(NonNull<TVMFFITypeAttrColumn>);
37
38unsafe impl Send for TypeAttrColumn {}
42unsafe impl Sync for TypeAttrColumn {}
43
44impl TypeAttrColumn {
45 pub fn new(name: &str) -> Option<Self> {
47 unsafe {
48 let name = TVMFFIByteArray::from_str(name);
49 NonNull::new(TVMFFIGetTypeAttrColumn(&name).cast_mut()).map(Self)
50 }
51 }
52
53 pub fn get(self, type_index: i32) -> Option<Any> {
55 let raw = self.get_raw(type_index)?;
56 if raw.type_index == TVMFFITypeIndex::kTVMFFINone as i32 {
57 return None;
58 }
59 Some(Any::from(unsafe { AnyView::from_raw_ffi_any(raw) }))
60 }
61
62 pub(crate) unsafe fn from_non_null(pointer: NonNull<TVMFFITypeAttrColumn>) -> Self {
63 Self(pointer)
64 }
65
66 pub(crate) fn as_ptr(self) -> *mut TVMFFITypeAttrColumn {
67 self.0.as_ptr()
68 }
69
70 pub(crate) fn get_raw(self, type_index: i32) -> Option<TVMFFIAny> {
72 unsafe {
73 let column = self.0.as_ref();
74 let index = type_index - column.begin_index;
75 if index < 0 || index >= column.size || column.data.is_null() {
76 None
77 } else {
78 Some(*column.data.offset(index as isize))
79 }
80 }
81 }
82}
83
84pub fn get_type_attr(type_index: i32, attr_name: &str) -> Option<Any> {
86 TypeAttrColumn::new(attr_name)?.get(type_index)
87}
88
89#[derive(Clone, Copy)]
91pub struct FieldGetter {
92 owner_type_index: i32,
93 owner_type_depth: i32,
94 field_offset: i64,
95 getter: TVMFFIFieldGetter,
96}
97
98impl FieldGetter {
99 pub fn new(type_index: i32, field_name: &str) -> Result<Self> {
101 let type_info = unsafe { TVMFFIGetTypeInfo(type_index) };
102 if type_info.is_null() {
103 return Err(Error::new(
104 TYPE_ERROR,
105 &format!("Cannot find type info for type_index={type_index}"),
106 "",
107 ));
108 }
109
110 let field = unsafe { find_field(type_info, field_name) }.ok_or_else(|| {
111 let type_key = unsafe { (*type_info).type_key.as_str() };
112 Error::new(
113 TYPE_ERROR,
114 &format!("Cannot find reflected field `{field_name}` in type `{type_key}`"),
115 "",
116 )
117 })?;
118 let field = unsafe { field.as_ref() };
119 let getter = field.getter.ok_or_else(|| {
120 Error::new(
121 TYPE_ERROR,
122 &format!("Reflected field `{}` has no getter", field.name.as_str()),
123 "",
124 )
125 })?;
126 Ok(Self {
127 owner_type_index: type_index,
128 owner_type_depth: unsafe { (*type_info).type_depth },
129 field_offset: field.offset,
130 getter,
131 })
132 }
133
134 pub fn get_any<N: ObjectCore>(&self, object: &N) -> Result<Any> {
138 let object_pointer = std::ptr::from_ref(object);
139 let header = object_pointer.cast::<TVMFFIObject>();
140 let dynamic_type_index = unsafe { (*header).type_index };
141 if !unsafe {
142 is_type_or_subtype(
143 dynamic_type_index,
144 self.owner_type_index,
145 self.owner_type_depth,
146 )
147 } {
148 return Err(Error::new(
149 TYPE_ERROR,
150 &format!(
151 "Cannot read a field of type_index={} from object type_index={dynamic_type_index}",
152 self.owner_type_index
153 ),
154 "",
155 ));
156 }
157
158 let field_address = unsafe {
159 object_pointer
160 .cast::<u8>()
161 .offset(self.field_offset as isize)
162 .cast_mut()
163 .cast::<c_void>()
164 };
165 let mut result = Any::new();
166 if unsafe { (self.getter)(field_address, Any::as_data_ptr(&mut result)) } != 0 {
167 return Err(Error::from_raised());
168 }
169 Ok(result)
170 }
171
172 pub fn get<N, T>(&self, object: &N) -> Result<T>
174 where
175 N: ObjectCore,
176 T: TryFrom<Any, Error = Error>,
177 {
178 T::try_from(self.get_any(object)?)
179 }
180}
181
182unsafe fn find_field(
183 type_info: *const crate::tvm_ffi_sys::TVMFFITypeInfo,
184 field_name: &str,
185) -> Option<NonNull<TVMFFIFieldInfo>> {
186 if let Some(field) = find_field_at_level(type_info, field_name) {
188 return Some(field);
189 }
190 for depth in (0..(*type_info).type_depth).rev() {
191 let ancestor = *(*type_info).type_acenstors.add(depth as usize);
192 if let Some(field) = find_field_at_level(ancestor, field_name) {
193 return Some(field);
194 }
195 }
196 None
197}
198
199unsafe fn find_field_at_level(
200 type_info: *const crate::tvm_ffi_sys::TVMFFITypeInfo,
201 field_name: &str,
202) -> Option<NonNull<TVMFFIFieldInfo>> {
203 if type_info.is_null() || (*type_info).fields.is_null() {
204 return None;
205 }
206 for index in 0..(*type_info).num_fields as usize {
207 let field = (*type_info).fields.add(index);
208 if (*field).name.as_str() == field_name {
209 return NonNull::new(field.cast_mut());
210 }
211 }
212 None
213}
214
215unsafe fn is_type_or_subtype(
216 dynamic_type_index: i32,
217 target_type_index: i32,
218 target_type_depth: i32,
219) -> bool {
220 if dynamic_type_index == target_type_index {
221 return true;
222 }
223 let dynamic_info = TVMFFIGetTypeInfo(dynamic_type_index);
224 if dynamic_info.is_null()
225 || (*dynamic_info).type_depth <= target_type_depth
226 || (*dynamic_info).type_acenstors.is_null()
227 {
228 return false;
229 }
230 let ancestor = *(*dynamic_info)
231 .type_acenstors
232 .add(target_type_depth as usize);
233 !ancestor.is_null() && (*ancestor).type_index == target_type_index
234}