1#![expect(dead_code)]
2
3use libc::{c_char, c_uint};
4
5use super::MetadataKindId;
6use super::ffi::{AttributeKind, BasicBlock, Context, Metadata, Module, Type, Value};
7use crate::llvm::{Bool, Builder};
8
9pub(crate) type CTypeTreeRef = *mut EnzymeTypeTree;
11
12#[repr(C)]
13#[derive(#[automatically_derived]
impl ::core::fmt::Debug for EnzymeTypeTree {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"EnzymeTypeTree", "_unused", &&self._unused)
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for EnzymeTypeTree { }Copy, #[automatically_derived]
impl ::core::clone::Clone for EnzymeTypeTree {
#[inline]
fn clone(&self) -> EnzymeTypeTree {
let _: ::core::clone::AssertParamIsClone<[u8; 0]>;
*self
}
}Clone)]
14pub(crate) struct EnzymeTypeTree {
15 _unused: [u8; 0],
16}
17
18#[repr(u32)]
19#[derive(#[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::fmt::Debug for CConcreteType {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
CConcreteType::DT_Anything => "DT_Anything",
CConcreteType::DT_Integer => "DT_Integer",
CConcreteType::DT_Pointer => "DT_Pointer",
CConcreteType::DT_Half => "DT_Half",
CConcreteType::DT_Float => "DT_Float",
CConcreteType::DT_Double => "DT_Double",
CConcreteType::DT_Unknown => "DT_Unknown",
CConcreteType::DT_FP128 => "DT_FP128",
})
}
}Debug, #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::marker::Copy for CConcreteType { }Copy, #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::clone::Clone for CConcreteType {
#[inline]
fn clone(&self) -> CConcreteType { *self }
}Clone, #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::hash::Hash for CConcreteType {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
let __self_discr = ::core::intrinsics::discriminant_value(self);
::core::hash::Hash::hash(&__self_discr, state)
}
}Hash, #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::cmp::PartialEq for CConcreteType {
#[inline]
fn eq(&self, other: &CConcreteType) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::cmp::Eq for CConcreteType {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq)]
20#[allow(non_camel_case_types)]
21pub(crate) enum CConcreteType {
22 DT_Anything = 0,
23 DT_Integer = 1,
24 DT_Pointer = 2,
25 DT_Half = 3,
26 DT_Float = 4,
27 DT_Double = 5,
28 DT_Unknown = 6,
29 DT_FP128 = 9,
30}
31
32pub(crate) struct TypeTree {
33 pub(crate) inner: CTypeTreeRef,
34}
35
36#[link(name = "llvm-wrapper", kind = "static")]
37unsafe extern "C" {
38 pub(crate) safe fn LLVMRustHasMetadata(I: &Value, KindID: MetadataKindId) -> bool;
40 pub(crate) fn LLVMRustEraseInstUntilInclusive(BB: &BasicBlock, I: &Value);
41 pub(crate) fn LLVMRustGetLastInstruction<'a>(BB: &BasicBlock) -> Option<&'a Value>;
42 pub(crate) fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>;
43 pub(crate) fn LLVMRustEraseInstFromParent(V: &Value);
44 pub(crate) fn LLVMRustGetTerminator<'a>(B: &BasicBlock) -> &'a Value;
45 pub(crate) fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
46 pub(crate) fn LLVMRustHasAttributeAtIndex(V: &Value, i: c_uint, Kind: AttributeKind) -> bool;
47 pub(crate) fn LLVMRustGetArrayNumElements(Ty: &Type) -> u64;
48 pub(crate) fn LLVMRustHasFnAttribute(
49 F: &Value,
50 Name: *const c_char,
51 NameLen: libc::size_t,
52 ) -> bool;
53 pub(crate) fn LLVMRustRemoveFnAttribute(F: &Value, Name: *const c_char, NameLen: libc::size_t);
54 pub(crate) fn LLVMGetFirstFunction(M: &Module) -> Option<&Value>;
55 pub(crate) fn LLVMGetNextFunction(Fn: &Value) -> Option<&Value>;
56 pub(crate) fn LLVMRustRemoveEnumAttributeAtIndex(
57 Fn: &Value,
58 index: c_uint,
59 kind: AttributeKind,
60 );
61 pub(crate) fn LLVMRustPositionBefore<'a>(B: &'a Builder<'_>, I: &'a Value);
62 pub(crate) fn LLVMRustPositionAfter<'a>(B: &'a Builder<'_>, I: &'a Value);
63 pub(crate) fn LLVMRustGetFunctionCall(
64 F: &Value,
65 name: *const c_char,
66 NameLen: libc::size_t,
67 ) -> Option<&Value>;
68
69}
70
71unsafe extern "C" {
72 pub(crate) fn LLVMDumpModule(M: &Module);
74 pub(crate) fn LLVMDumpValue(V: &Value);
75 pub(crate) fn LLVMGetFunctionCallConv(F: &Value) -> c_uint;
76 pub(crate) fn LLVMGetParams(Fnc: &Value, params: *mut &Value);
77 pub(crate) fn LLVMGetNamedFunction(M: &Module, Name: *const c_char) -> Option<&Value>;
78}
79
80#[repr(C)]
81#[derive(#[automatically_derived]
impl ::core::marker::Copy for LLVMRustVerifierFailureAction { }Copy, #[automatically_derived]
impl ::core::clone::Clone for LLVMRustVerifierFailureAction {
#[inline]
fn clone(&self) -> LLVMRustVerifierFailureAction { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for LLVMRustVerifierFailureAction {
#[inline]
fn eq(&self, other: &LLVMRustVerifierFailureAction) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq)]
82pub(crate) enum LLVMRustVerifierFailureAction {
83 LLVMAbortProcessAction = 0,
84 LLVMPrintMessageAction = 1,
85 LLVMReturnStatusAction = 2,
86}
87
88pub(crate) use self::Enzyme_AD::*;
89
90pub(crate) mod Enzyme_AD {
91 use std::ffi::{c_char, c_void};
92 use std::sync::{Mutex, MutexGuard, OnceLock};
93
94 use rustc_middle::bug;
95 use rustc_session::config::{Sysroot, host_tuple};
96 use rustc_session::filesearch;
97
98 use super::{CConcreteType, CTypeTreeRef, Context};
99 use crate::llvm::{EnzymeTypeTree, LLVMRustVersionMajor};
100
101 type EnzymeSetCLBoolFn = unsafe extern "C" fn(*mut c_void, u8);
102 type EnzymeSetCLStringFn = unsafe extern "C" fn(*mut c_void, *const c_char);
103
104 type EnzymeNewTypeTreeFn = unsafe extern "C" fn() -> CTypeTreeRef;
105 type EnzymeNewTypeTreeCTFn = unsafe extern "C" fn(CConcreteType, &Context) -> CTypeTreeRef;
106 type EnzymeNewTypeTreeTRFn = unsafe extern "C" fn(CTypeTreeRef) -> CTypeTreeRef;
107 type EnzymeFreeTypeTreeFn = unsafe extern "C" fn(CTypeTreeRef);
108 type EnzymeMergeTypeTreeFn = unsafe extern "C" fn(CTypeTreeRef, CTypeTreeRef) -> bool;
109 type EnzymeTypeTreeOnlyEqFn = unsafe extern "C" fn(CTypeTreeRef, i64);
110 type EnzymeTypeTreeData0EqFn = unsafe extern "C" fn(CTypeTreeRef);
111 type EnzymeTypeTreeShiftIndiciesEqFn =
112 unsafe extern "C" fn(CTypeTreeRef, *const c_char, i64, i64, u64);
113 type EnzymeTypeTreeInsertEqFn =
114 unsafe extern "C" fn(CTypeTreeRef, *const i64, usize, CConcreteType, &Context);
115 type EnzymeTypeTreeToStringFn = unsafe extern "C" fn(CTypeTreeRef) -> *const c_char;
116 type EnzymeTypeTreeToStringFreeFn = unsafe extern "C" fn(*const c_char);
117
118 #[allow(non_snake_case)]
119 pub(crate) struct EnzymeWrapper {
120 EnzymeNewTypeTree: EnzymeNewTypeTreeFn,
121 EnzymeNewTypeTreeCT: EnzymeNewTypeTreeCTFn,
122 EnzymeNewTypeTreeTR: EnzymeNewTypeTreeTRFn,
123 EnzymeFreeTypeTree: EnzymeFreeTypeTreeFn,
124 EnzymeMergeTypeTree: EnzymeMergeTypeTreeFn,
125 EnzymeTypeTreeOnlyEq: EnzymeTypeTreeOnlyEqFn,
126 EnzymeTypeTreeData0Eq: EnzymeTypeTreeData0EqFn,
127 EnzymeTypeTreeShiftIndiciesEq: EnzymeTypeTreeShiftIndiciesEqFn,
128 EnzymeTypeTreeInsertEq: EnzymeTypeTreeInsertEqFn,
129 EnzymeTypeTreeToString: EnzymeTypeTreeToStringFn,
130 EnzymeTypeTreeToStringFree: EnzymeTypeTreeToStringFreeFn,
131
132 EnzymePrintPerf: *mut c_void,
133 EnzymePrintActivity: *mut c_void,
134 EnzymePrintType: *mut c_void,
135 EnzymeFunctionToAnalyze: *mut c_void,
136 EnzymePrint: *mut c_void,
137 EnzymeStrictAliasing: *mut c_void,
138 EnzymeInline: *mut c_void,
139 EnzymeMaxTypeDepth: *mut c_void,
140 RustTypeRules: *mut c_void,
141 looseTypeAnalysis: *mut c_void,
142
143 EnzymeSetCLBool: EnzymeSetCLBoolFn,
144 EnzymeSetCLString: EnzymeSetCLStringFn,
145 pub registerEnzymeAndPassPipeline: *const c_void,
146 lib: libloading::Library,
147 }
148
149 unsafe impl Sync for EnzymeWrapper {}
150 unsafe impl Send for EnzymeWrapper {}
151
152 fn load_ptr_by_symbol_mut_void(
153 lib: &libloading::Library,
154 bytes: &[u8],
155 ) -> Result<*mut c_void, libloading::Error> {
156 unsafe {
157 let s: libloading::Symbol<'_, *mut c_void> = lib.get(bytes)?;
158 let s = s.try_as_raw_ptr().unwrap();
160 Ok(s)
161 }
162 }
163
164 macro_rules! load_ptrs_by_symbols_mut_void {
170 ($lib:expr, $($name:ident),* $(,)?) => {
171 $(
172 #[allow(non_snake_case)]
173 let $name = load_ptr_by_symbol_mut_void(&$lib, stringify!($name).as_bytes())?;
174 )*
175 };
176 }
177
178 macro_rules! load_ptrs_by_symbols_fn {
184 ($lib:expr, $($name:ident : $ty:ty),* $(,)?) => {
185 $(
186 #[allow(non_snake_case)]
187 let $name: $ty = *unsafe { $lib.get::<$ty>(stringify!($name).as_bytes())? };
188 )*
189 };
190 }
191
192 static ENZYME_INSTANCE: OnceLock<Mutex<EnzymeWrapper>> = OnceLock::new();
193
194 #[derive(#[automatically_derived]
impl ::core::fmt::Debug for EnzymeLibraryError {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
EnzymeLibraryError::NotFound { err: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"NotFound", "err", &__self_0),
EnzymeLibraryError::LoadFailed { err: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"LoadFailed", "err", &__self_0),
}
}
}Debug)]
195 pub(crate) enum EnzymeLibraryError {
196 NotFound { err: String },
197 LoadFailed { err: String },
198 }
199
200 impl From<libloading::Error> for EnzymeLibraryError {
201 fn from(err: libloading::Error) -> Self {
202 Self::LoadFailed { err: ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", err))
})format!("{err:?}") }
203 }
204 }
205
206 impl EnzymeWrapper {
207 pub(crate) fn get_or_init(
210 sysroot: &rustc_session::config::Sysroot,
211 ) -> Result<MutexGuard<'static, Self>, EnzymeLibraryError> {
212 let mtx: &'static Mutex<EnzymeWrapper> = ENZYME_INSTANCE.get_or_try_init(|| {
213 let w = Self::call_dynamic(sysroot)?;
214 Ok::<_, EnzymeLibraryError>(Mutex::new(w))
215 })?;
216
217 Ok(mtx.lock().unwrap())
218 }
219
220 pub(crate) fn get_instance() -> MutexGuard<'static, Self> {
222 ENZYME_INSTANCE
223 .get()
224 .expect("EnzymeWrapper not initialized. Call get_or_init with sysroot first.")
225 .lock()
226 .unwrap()
227 }
228
229 pub(crate) fn new_type_tree(&self) -> CTypeTreeRef {
230 unsafe { (self.EnzymeNewTypeTree)() }
231 }
232
233 pub(crate) fn new_type_tree_ct(
234 &self,
235 t: CConcreteType,
236 ctx: &Context,
237 ) -> *mut EnzymeTypeTree {
238 unsafe { (self.EnzymeNewTypeTreeCT)(t, ctx) }
239 }
240
241 pub(crate) fn new_type_tree_tr(&self, tree: CTypeTreeRef) -> CTypeTreeRef {
242 unsafe { (self.EnzymeNewTypeTreeTR)(tree) }
243 }
244
245 pub(crate) fn free_type_tree(&self, tree: CTypeTreeRef) {
246 unsafe { (self.EnzymeFreeTypeTree)(tree) }
247 }
248
249 pub(crate) fn merge_type_tree(&self, tree1: CTypeTreeRef, tree2: CTypeTreeRef) -> bool {
250 unsafe { (self.EnzymeMergeTypeTree)(tree1, tree2) }
251 }
252
253 pub(crate) fn tree_only_eq(&self, tree: CTypeTreeRef, num: i64) {
254 unsafe { (self.EnzymeTypeTreeOnlyEq)(tree, num) }
255 }
256
257 pub(crate) fn tree_data0_eq(&self, tree: CTypeTreeRef) {
258 unsafe { (self.EnzymeTypeTreeData0Eq)(tree) }
259 }
260
261 pub(crate) fn shift_indicies_eq(
262 &self,
263 tree: CTypeTreeRef,
264 data_layout: *const c_char,
265 offset: i64,
266 max_size: i64,
267 add_offset: u64,
268 ) {
269 unsafe {
270 (self.EnzymeTypeTreeShiftIndiciesEq)(
271 tree,
272 data_layout,
273 offset,
274 max_size,
275 add_offset,
276 )
277 }
278 }
279
280 pub(crate) fn tree_insert_eq(
281 &self,
282 tree: CTypeTreeRef,
283 indices: *const i64,
284 len: usize,
285 ct: CConcreteType,
286 ctx: &Context,
287 ) {
288 unsafe { (self.EnzymeTypeTreeInsertEq)(tree, indices, len, ct, ctx) }
289 }
290
291 pub(crate) fn tree_to_string(&self, tree: *mut EnzymeTypeTree) -> *const c_char {
292 unsafe { (self.EnzymeTypeTreeToString)(tree) }
293 }
294
295 pub(crate) fn tree_to_string_free(&self, ch: *const c_char) {
296 unsafe { (self.EnzymeTypeTreeToStringFree)(ch) }
297 }
298
299 pub(crate) fn get_max_type_depth(&self) -> usize {
300 unsafe { std::ptr::read::<u32>(self.EnzymeMaxTypeDepth as *const u32) as usize }
301 }
302
303 pub(crate) fn set_print_perf(&mut self, print: bool) {
304 unsafe {
305 (self.EnzymeSetCLBool)(self.EnzymePrintPerf, print as u8);
306 }
307 }
308
309 pub(crate) fn set_print_activity(&mut self, print: bool) {
310 unsafe {
311 (self.EnzymeSetCLBool)(self.EnzymePrintActivity, print as u8);
312 }
313 }
314
315 pub(crate) fn set_print_type(&mut self, print: bool) {
316 unsafe {
317 (self.EnzymeSetCLBool)(self.EnzymePrintType, print as u8);
318 }
319 }
320
321 pub(crate) fn set_print_type_fun(&mut self, fun_name: &str) {
322 let c_fun_name = std::ffi::CString::new(fun_name)
323 .unwrap_or_else(|err| ::rustc_middle::util::bug::bug_fmt(format_args!("failed to set_print_type_fun: {0}",
err))bug!("failed to set_print_type_fun: {err}"));
324 unsafe {
325 (self.EnzymeSetCLString)(
326 self.EnzymeFunctionToAnalyze,
327 c_fun_name.as_ptr() as *const c_char,
328 );
329 }
330 }
331
332 pub(crate) fn set_print(&mut self, print: bool) {
333 unsafe {
334 (self.EnzymeSetCLBool)(self.EnzymePrint, print as u8);
335 }
336 }
337
338 pub(crate) fn set_strict_aliasing(&mut self, strict: bool) {
339 unsafe {
340 (self.EnzymeSetCLBool)(self.EnzymeStrictAliasing, strict as u8);
341 }
342 }
343
344 pub(crate) fn set_loose_types(&mut self, loose: bool) {
345 unsafe {
346 (self.EnzymeSetCLBool)(self.looseTypeAnalysis, loose as u8);
347 }
348 }
349
350 pub(crate) fn set_inline(&mut self, val: bool) {
351 unsafe {
352 (self.EnzymeSetCLBool)(self.EnzymeInline, val as u8);
353 }
354 }
355
356 pub(crate) fn set_rust_rules(&mut self, val: bool) {
357 unsafe {
358 (self.EnzymeSetCLBool)(self.RustTypeRules, val as u8);
359 }
360 }
361
362 #[allow(non_snake_case)]
363 fn call_dynamic(
364 sysroot: &rustc_session::config::Sysroot,
365 ) -> Result<Self, EnzymeLibraryError> {
366 let enzyme_path = Self::get_enzyme_path(sysroot)?;
367 let lib = unsafe { libloading::Library::new(enzyme_path)? };
368
369 #[allow(non_snake_case)]
let EnzymeSetCLString: EnzymeSetCLStringFn =
*unsafe {
lib.get::<EnzymeSetCLStringFn>("EnzymeSetCLString".as_bytes())?
};load_ptrs_by_symbols_fn!(
370 lib,
371 EnzymeNewTypeTree: EnzymeNewTypeTreeFn,
372 EnzymeNewTypeTreeCT: EnzymeNewTypeTreeCTFn,
373 EnzymeNewTypeTreeTR: EnzymeNewTypeTreeTRFn,
374 EnzymeFreeTypeTree: EnzymeFreeTypeTreeFn,
375 EnzymeMergeTypeTree: EnzymeMergeTypeTreeFn,
376 EnzymeTypeTreeOnlyEq: EnzymeTypeTreeOnlyEqFn,
377 EnzymeTypeTreeData0Eq: EnzymeTypeTreeData0EqFn,
378 EnzymeTypeTreeShiftIndiciesEq: EnzymeTypeTreeShiftIndiciesEqFn,
379 EnzymeTypeTreeInsertEq: EnzymeTypeTreeInsertEqFn,
380 EnzymeTypeTreeToString: EnzymeTypeTreeToStringFn,
381 EnzymeTypeTreeToStringFree: EnzymeTypeTreeToStringFreeFn,
382 EnzymeSetCLBool: EnzymeSetCLBoolFn,
383 EnzymeSetCLString: EnzymeSetCLStringFn,
384 );
385
386 #[allow(non_snake_case)]
let looseTypeAnalysis =
load_ptr_by_symbol_mut_void(&lib, "looseTypeAnalysis".as_bytes())?;load_ptrs_by_symbols_mut_void!(
387 lib,
388 registerEnzymeAndPassPipeline,
389 EnzymePrintPerf,
390 EnzymePrintActivity,
391 EnzymePrintType,
392 EnzymeFunctionToAnalyze,
393 EnzymePrint,
394 EnzymeStrictAliasing,
395 EnzymeInline,
396 EnzymeMaxTypeDepth,
397 RustTypeRules,
398 looseTypeAnalysis,
399 );
400
401 Ok(Self {
402 EnzymeNewTypeTree,
403 EnzymeNewTypeTreeCT,
404 EnzymeNewTypeTreeTR,
405 EnzymeFreeTypeTree,
406 EnzymeMergeTypeTree,
407 EnzymeTypeTreeOnlyEq,
408 EnzymeTypeTreeData0Eq,
409 EnzymeTypeTreeShiftIndiciesEq,
410 EnzymeTypeTreeInsertEq,
411 EnzymeTypeTreeToString,
412 EnzymeTypeTreeToStringFree,
413 EnzymePrintPerf,
414 EnzymePrintActivity,
415 EnzymePrintType,
416 EnzymeFunctionToAnalyze,
417 EnzymePrint,
418 EnzymeStrictAliasing,
419 EnzymeInline,
420 EnzymeMaxTypeDepth,
421 RustTypeRules,
422 looseTypeAnalysis,
423 EnzymeSetCLBool,
424 EnzymeSetCLString,
425 registerEnzymeAndPassPipeline,
426 lib,
427 })
428 }
429
430 fn get_enzyme_path(sysroot: &Sysroot) -> Result<String, EnzymeLibraryError> {
431 let llvm_version_major = unsafe { LLVMRustVersionMajor() };
432
433 let path_buf = sysroot
434 .all_paths()
435 .map(|sysroot_path| {
436 filesearch::make_target_lib_path(sysroot_path, host_tuple())
437 .join("lib")
438 .with_file_name(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("libEnzyme-{0}",
llvm_version_major))
})format!("libEnzyme-{llvm_version_major}"))
439 .with_extension(std::env::consts::DLL_EXTENSION)
440 })
441 .find(|f| f.exists())
442 .ok_or_else(|| {
443 let candidates = sysroot
444 .all_paths()
445 .map(|p| p.join("lib").display().to_string())
446 .collect::<Vec<String>>()
447 .join("\n* ");
448 EnzymeLibraryError::NotFound {
449 err: ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("failed to find a `libEnzyme-{0}` folder in the sysroot candidates:\n* {1}",
llvm_version_major, candidates))
})format!(
450 "failed to find a `libEnzyme-{llvm_version_major}` folder \
451 in the sysroot candidates:\n* {candidates}"
452 ),
453 }
454 })?;
455
456 Ok(path_buf
457 .to_str()
458 .ok_or_else(|| EnzymeLibraryError::LoadFailed {
459 err: ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("invalid UTF-8 in path: {0}",
path_buf.display()))
})format!("invalid UTF-8 in path: {}", path_buf.display()),
460 })?
461 .to_string())
462 }
463 }
464}
465
466impl TypeTree {
467 pub(crate) fn new() -> TypeTree {
468 let wrapper = EnzymeWrapper::get_instance();
469 let inner = wrapper.new_type_tree();
470 TypeTree { inner }
471 }
472
473 pub(crate) fn from_type(t: CConcreteType, ctx: &Context) -> TypeTree {
474 let wrapper = EnzymeWrapper::get_instance();
475 let inner = wrapper.new_type_tree_ct(t, ctx);
476 TypeTree { inner }
477 }
478
479 pub(crate) fn merge(self, other: Self) -> Self {
480 let wrapper = EnzymeWrapper::get_instance();
481 wrapper.merge_type_tree(self.inner, other.inner);
482 drop(other);
483 self
484 }
485
486 #[must_use]
487 pub(crate) fn shift(
488 self,
489 layout: &str,
490 offset: isize,
491 max_size: isize,
492 add_offset: usize,
493 ) -> Self {
494 let layout = std::ffi::CString::new(layout).unwrap();
495 let wrapper = EnzymeWrapper::get_instance();
496 wrapper.shift_indicies_eq(
497 self.inner,
498 layout.as_ptr(),
499 offset as i64,
500 max_size as i64,
501 add_offset as u64,
502 );
503
504 self
505 }
506
507 pub(crate) fn insert(&mut self, indices: &[i64], ct: CConcreteType, ctx: &Context) {
508 let wrapper = EnzymeWrapper::get_instance();
509 wrapper.tree_insert_eq(self.inner, indices.as_ptr(), indices.len(), ct, ctx);
510 }
511}
512
513impl Clone for TypeTree {
514 fn clone(&self) -> Self {
515 let wrapper = EnzymeWrapper::get_instance();
516 let inner = wrapper.new_type_tree_tr(self.inner);
517 TypeTree { inner }
518 }
519}
520
521impl std::fmt::Display for TypeTree {
522 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
523 let wrapper = EnzymeWrapper::get_instance();
524 let ptr = wrapper.tree_to_string(self.inner);
525 let cstr = unsafe { std::ffi::CStr::from_ptr(ptr) };
526 match cstr.to_str() {
527 Ok(x) => f.write_fmt(format_args!("{0}", x))write!(f, "{}", x)?,
528 Err(err) => f.write_fmt(format_args!("could not parse: {0}", err))write!(f, "could not parse: {}", err)?,
529 }
530
531 wrapper.tree_to_string_free(ptr);
533
534 Ok(())
535 }
536}
537
538impl std::fmt::Debug for TypeTree {
539 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
540 <Self as std::fmt::Display>::fmt(self, f)
541 }
542}
543
544impl Drop for TypeTree {
545 fn drop(&mut self) {
546 let wrapper = EnzymeWrapper::get_instance();
547 wrapper.free_type_tree(self.inner)
548 }
549}