binaryninja/
types.rs

1// Copyright 2021-2025 Vector 35 Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14#![allow(unused)]
15
16// TODO : More widely enforce the use of ref_from_raw vs just from_raw to simplify internal binding usage?  Perhaps remove from_raw functions?
17// TODO : Add documentation and fix examples
18// TODO : Test the get_enumeration and get_structure methods
19
20use binaryninjacore_sys::*;
21
22use crate::{
23    architecture::{Architecture, CoreArchitecture},
24    binary_view::{BinaryView, BinaryViewExt},
25    calling_convention::CoreCallingConvention,
26    rc::*,
27    string::{BnString, IntoCStr},
28};
29
30use crate::confidence::{Conf, MAX_CONFIDENCE, MIN_CONFIDENCE};
31use crate::string::{raw_to_string, strings_to_string_list};
32use crate::type_container::TypeContainer;
33use crate::variable::{Variable, VariableSourceType};
34use std::borrow::Cow;
35use std::num::NonZeroUsize;
36use std::ops::{Index, IndexMut};
37use std::{
38    collections::HashSet,
39    ffi::CStr,
40    fmt::{Debug, Display, Formatter},
41    hash::{Hash, Hasher},
42    iter::IntoIterator,
43};
44
45pub type StructureType = BNStructureVariant;
46pub type ReferenceType = BNReferenceType;
47pub type TypeClass = BNTypeClass;
48pub type NamedTypeReferenceClass = BNNamedTypeReferenceClass;
49pub type MemberAccess = BNMemberAccess;
50pub type MemberScope = BNMemberScope;
51pub type IntegerDisplayType = BNIntegerDisplayType;
52pub type PointerBaseType = BNPointerBaseType;
53
54#[derive(PartialEq, Eq, Hash)]
55pub struct TypeBuilder {
56    pub(crate) handle: *mut BNTypeBuilder,
57}
58
59impl TypeBuilder {
60    pub fn new(t: &Type) -> Self {
61        unsafe { Self::from_raw(BNCreateTypeBuilderFromType(t.handle)) }
62    }
63
64    pub(crate) unsafe fn from_raw(handle: *mut BNTypeBuilder) -> Self {
65        debug_assert!(!handle.is_null());
66        Self { handle }
67    }
68
69    // Chainable terminal
70    pub fn finalize(&self) -> Ref<Type> {
71        unsafe { Type::ref_from_raw(BNFinalizeTypeBuilder(self.handle)) }
72    }
73
74    // Settable properties
75
76    pub fn set_can_return<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
77        let mut bool_with_confidence = value.into().into();
78        unsafe { BNSetFunctionTypeBuilderCanReturn(self.handle, &mut bool_with_confidence) };
79        self
80    }
81
82    pub fn set_pure<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
83        let mut bool_with_confidence = value.into().into();
84        unsafe { BNSetTypeBuilderPure(self.handle, &mut bool_with_confidence) };
85        self
86    }
87
88    pub fn set_const<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
89        let mut bool_with_confidence = value.into().into();
90        unsafe { BNTypeBuilderSetConst(self.handle, &mut bool_with_confidence) };
91        self
92    }
93
94    pub fn set_volatile<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
95        let mut bool_with_confidence = value.into().into();
96        unsafe { BNTypeBuilderSetVolatile(self.handle, &mut bool_with_confidence) };
97        self
98    }
99
100    pub fn set_pointer_base(&self, base_type: PointerBaseType, base_offset: i64) -> &Self {
101        unsafe { BNSetTypeBuilderPointerBase(self.handle, base_type, base_offset) }
102        self
103    }
104
105    pub fn set_child_type<'a, T: Into<Conf<&'a Type>>>(&self, ty: T) -> &Self {
106        let mut type_with_confidence = Conf::<&Type>::into_raw(ty.into());
107        unsafe { BNTypeBuilderSetChildType(self.handle, &mut type_with_confidence) };
108        self
109    }
110
111    /// This is an alias for [`Self::set_child_type`].
112    pub fn set_target<'a, T: Into<Conf<&'a Type>>>(&self, ty: T) -> &Self {
113        self.set_child_type(ty)
114    }
115
116    /// This is an alias for [`Self::set_child_type`].
117    pub fn set_element_type<'a, T: Into<Conf<&'a Type>>>(&self, ty: T) -> &Self {
118        self.set_child_type(ty)
119    }
120
121    /// This is an alias for [`Self::set_child_type`].
122    pub fn set_return_value<'a, T: Into<Conf<&'a Type>>>(&self, ty: T) -> &Self {
123        self.set_child_type(ty)
124    }
125
126    // Readable properties
127
128    pub fn type_class(&self) -> TypeClass {
129        unsafe { BNGetTypeBuilderClass(self.handle) }
130    }
131
132    pub fn width(&self) -> u64 {
133        unsafe { BNGetTypeBuilderWidth(self.handle) }
134    }
135
136    pub fn alignment(&self) -> usize {
137        unsafe { BNGetTypeBuilderAlignment(self.handle) }
138    }
139
140    pub fn is_signed(&self) -> Conf<bool> {
141        unsafe { BNIsTypeBuilderSigned(self.handle).into() }
142    }
143
144    pub fn is_const(&self) -> Conf<bool> {
145        unsafe { BNIsTypeBuilderConst(self.handle).into() }
146    }
147
148    pub fn is_volatile(&self) -> Conf<bool> {
149        unsafe { BNIsTypeBuilderVolatile(self.handle).into() }
150    }
151
152    pub fn is_floating_point(&self) -> bool {
153        unsafe { BNIsTypeBuilderFloatingPoint(self.handle) }
154    }
155
156    pub fn child_type(&self) -> Option<Conf<Ref<Type>>> {
157        let raw_target = unsafe { BNGetTypeBuilderChildType(self.handle) };
158        match raw_target.type_.is_null() {
159            false => Some(Conf::<Ref<Type>>::from_owned_raw(raw_target)),
160            true => None,
161        }
162    }
163
164    /// This is an alias for [`Self::child_type`].
165    pub fn target(&self) -> Option<Conf<Ref<Type>>> {
166        self.child_type()
167    }
168
169    /// This is an alias for [`Self::child_type`].
170    pub fn element_type(&self) -> Option<Conf<Ref<Type>>> {
171        self.child_type()
172    }
173
174    /// This is an alias for [`Self::child_type`].
175    pub fn return_value(&self) -> Option<Conf<Ref<Type>>> {
176        self.child_type()
177    }
178
179    pub fn calling_convention(&self) -> Option<Conf<Ref<CoreCallingConvention>>> {
180        let raw_convention_confidence = unsafe { BNGetTypeBuilderCallingConvention(self.handle) };
181        match raw_convention_confidence.convention.is_null() {
182            false => Some(Conf::<Ref<CoreCallingConvention>>::from_owned_raw(
183                raw_convention_confidence,
184            )),
185            true => None,
186        }
187    }
188
189    pub fn parameters(&self) -> Option<Vec<FunctionParameter>> {
190        unsafe {
191            let mut count = 0;
192            let raw_parameters_ptr = BNGetTypeBuilderParameters(self.handle, &mut count);
193            match raw_parameters_ptr.is_null() {
194                false => {
195                    let raw_parameters = std::slice::from_raw_parts(raw_parameters_ptr, count);
196                    let parameters = raw_parameters
197                        .iter()
198                        .map(FunctionParameter::from_raw)
199                        .collect();
200                    BNFreeTypeParameterList(raw_parameters_ptr, count);
201                    Some(parameters)
202                }
203                true => None,
204            }
205        }
206    }
207
208    pub fn has_variable_arguments(&self) -> Conf<bool> {
209        unsafe { BNTypeBuilderHasVariableArguments(self.handle).into() }
210    }
211
212    pub fn can_return(&self) -> Conf<bool> {
213        unsafe { BNFunctionTypeBuilderCanReturn(self.handle).into() }
214    }
215
216    pub fn pure(&self) -> Conf<bool> {
217        unsafe { BNIsTypeBuilderPure(self.handle).into() }
218    }
219
220    // TODO: This naming is problematic... rename to `as_structure`?
221    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
222    pub fn get_structure(&self) -> Option<Ref<Structure>> {
223        let raw_struct_ptr = unsafe { BNGetTypeBuilderStructure(self.handle) };
224        match raw_struct_ptr.is_null() {
225            false => Some(unsafe { Structure::ref_from_raw(raw_struct_ptr) }),
226            true => None,
227        }
228    }
229
230    // TODO: This naming is problematic... rename to `as_enumeration`?
231    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
232    pub fn get_enumeration(&self) -> Option<Ref<Enumeration>> {
233        let raw_enum_ptr = unsafe { BNGetTypeBuilderEnumeration(self.handle) };
234        match raw_enum_ptr.is_null() {
235            false => Some(unsafe { Enumeration::ref_from_raw(raw_enum_ptr) }),
236            true => None,
237        }
238    }
239
240    // TODO: This naming is problematic... rename to `as_named_type_reference`?
241    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
242    pub fn get_named_type_reference(&self) -> Option<Ref<NamedTypeReference>> {
243        let raw_type_ref_ptr = unsafe { BNGetTypeBuilderNamedTypeReference(self.handle) };
244        match raw_type_ref_ptr.is_null() {
245            false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
246            true => None,
247        }
248    }
249
250    pub fn count(&self) -> u64 {
251        unsafe { BNGetTypeBuilderElementCount(self.handle) }
252    }
253
254    pub fn offset(&self) -> u64 {
255        unsafe { BNGetTypeBuilderOffset(self.handle) }
256    }
257
258    pub fn stack_adjustment(&self) -> Conf<i64> {
259        unsafe { BNGetTypeBuilderStackAdjustment(self.handle).into() }
260    }
261
262    pub fn pointer_base_type(&self) -> PointerBaseType {
263        unsafe { BNTypeBuilderGetPointerBaseType(self.handle) }
264    }
265
266    pub fn pointer_base_offset(&self) -> i64 {
267        unsafe { BNTypeBuilderGetPointerBaseOffset(self.handle) }
268    }
269
270    // TODO : This and properties
271    // pub fn tokens(&self) -> ? {}
272
273    pub fn void() -> Self {
274        unsafe { Self::from_raw(BNCreateVoidTypeBuilder()) }
275    }
276
277    pub fn bool() -> Self {
278        unsafe { Self::from_raw(BNCreateBoolTypeBuilder()) }
279    }
280
281    pub fn char() -> Self {
282        Self::int(1, true)
283    }
284
285    pub fn int(width: usize, is_signed: bool) -> Self {
286        let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
287
288        unsafe {
289            Self::from_raw(BNCreateIntegerTypeBuilder(
290                width,
291                &mut is_signed,
292                BnString::new("").as_ptr() as *mut _,
293            ))
294        }
295    }
296
297    pub fn named_int(width: usize, is_signed: bool, alt_name: &str) -> Self {
298        let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
299        // let alt_name = BnString::new(alt_name);
300        let alt_name = alt_name.to_cstr(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data
301
302        unsafe {
303            Self::from_raw(BNCreateIntegerTypeBuilder(
304                width,
305                &mut is_signed,
306                alt_name.as_ref().as_ptr() as _,
307            ))
308        }
309    }
310
311    pub fn float(width: usize) -> Self {
312        unsafe { Self::from_raw(BNCreateFloatTypeBuilder(width, c"".as_ptr())) }
313    }
314
315    pub fn named_float(width: usize, alt_name: &str) -> Self {
316        let alt_name = alt_name.to_cstr();
317        unsafe { Self::from_raw(BNCreateFloatTypeBuilder(width, alt_name.as_ptr())) }
318    }
319
320    pub fn array<'a, T: Into<Conf<&'a Type>>>(ty: T, count: u64) -> Self {
321        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
322        unsafe { Self::from_raw(BNCreateArrayTypeBuilder(&owned_raw_ty, count)) }
323    }
324
325    /// ## NOTE
326    ///
327    /// The C/C++ APIs require an associated architecture, but in the core we only query the default_int_size if the given width is 0.
328    ///
329    /// For simplicity's sake, that convention isn't followed, and you can query [`Architecture::default_integer_size`] if you need to.
330    pub fn enumeration<T: Into<Conf<bool>>>(
331        enumeration: &Enumeration,
332        width: NonZeroUsize,
333        is_signed: T,
334    ) -> Self {
335        unsafe {
336            Self::from_raw(BNCreateEnumerationTypeBuilder(
337                // TODO: We pass nullptr arch, really we should not even be passing arch.
338                std::ptr::null_mut(),
339                enumeration.handle,
340                width.get(),
341                &mut is_signed.into().into(),
342            ))
343        }
344    }
345
346    pub fn structure(structure_type: &Structure) -> Self {
347        unsafe { Self::from_raw(BNCreateStructureTypeBuilder(structure_type.handle)) }
348    }
349
350    pub fn named_type(type_reference: NamedTypeReference) -> Self {
351        let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
352        let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
353        unsafe {
354            Self::from_raw(BNCreateNamedTypeReferenceBuilder(
355                type_reference.handle,
356                0,
357                1,
358                &mut is_const,
359                &mut is_volatile,
360            ))
361        }
362    }
363
364    pub fn named_type_from_type<T: Into<QualifiedName>>(name: T, t: &Type) -> Self {
365        let mut raw_name = QualifiedName::into_raw(name.into());
366        let id = c"";
367
368        let result = unsafe {
369            Self::from_raw(BNCreateNamedTypeReferenceBuilderFromTypeAndId(
370                id.as_ptr() as *mut _,
371                &mut raw_name,
372                t.handle,
373            ))
374        };
375        QualifiedName::free_raw(raw_name);
376        result
377    }
378
379    // TODO : BNCreateFunctionTypeBuilder
380
381    pub fn pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Self {
382        let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
383        let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
384        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
385        unsafe {
386            Self::from_raw(BNCreatePointerTypeBuilder(
387                arch.as_ref().handle,
388                &owned_raw_ty,
389                &mut is_const,
390                &mut is_volatile,
391                ReferenceType::PointerReferenceType,
392            ))
393        }
394    }
395
396    pub fn const_pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Self {
397        let mut is_const = Conf::new(true, MAX_CONFIDENCE).into();
398        let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
399        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
400        unsafe {
401            Self::from_raw(BNCreatePointerTypeBuilder(
402                arch.as_ref().handle,
403                &owned_raw_ty,
404                &mut is_const,
405                &mut is_volatile,
406                ReferenceType::PointerReferenceType,
407            ))
408        }
409    }
410
411    pub fn pointer_of_width<'a, T: Into<Conf<&'a Type>>>(
412        ty: T,
413        size: usize,
414        is_const: bool,
415        is_volatile: bool,
416        ref_type: Option<ReferenceType>,
417    ) -> Self {
418        let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
419        let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
420        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
421        unsafe {
422            Self::from_raw(BNCreatePointerTypeBuilderOfWidth(
423                size,
424                &owned_raw_ty,
425                &mut is_const,
426                &mut is_volatile,
427                ref_type.unwrap_or(ReferenceType::PointerReferenceType),
428            ))
429        }
430    }
431
432    pub fn pointer_with_options<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
433        arch: &A,
434        ty: T,
435        is_const: bool,
436        is_volatile: bool,
437        ref_type: Option<ReferenceType>,
438    ) -> Self {
439        let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
440        let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
441        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
442        unsafe {
443            Self::from_raw(BNCreatePointerTypeBuilder(
444                arch.as_ref().handle,
445                &owned_raw_ty,
446                &mut is_const,
447                &mut is_volatile,
448                ref_type.unwrap_or(ReferenceType::PointerReferenceType),
449            ))
450        }
451    }
452}
453
454impl Display for TypeBuilder {
455    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
456        write!(f, "{}", unsafe {
457            BnString::into_string(BNGetTypeBuilderString(self.handle, std::ptr::null_mut()))
458        })
459    }
460}
461
462impl Drop for TypeBuilder {
463    fn drop(&mut self) {
464        unsafe { BNFreeTypeBuilder(self.handle) };
465    }
466}
467
468#[repr(transparent)]
469pub struct Type {
470    pub handle: *mut BNType,
471}
472
473/// ```no_run
474/// # use crate::binaryninja::binary_view::BinaryViewExt;
475/// # use binaryninja::types::Type;
476/// let bv = binaryninja::load("example.bin").unwrap();
477/// let my_custom_type_1 = Type::named_int(5, false, "my_w");
478/// let my_custom_type_2 = Type::int(5, false);
479/// bv.define_user_type("int_1", &my_custom_type_1);
480/// bv.define_user_type("int_2", &my_custom_type_2);
481/// ```
482impl Type {
483    pub unsafe fn from_raw(handle: *mut BNType) -> Self {
484        debug_assert!(!handle.is_null());
485        Self { handle }
486    }
487
488    pub unsafe fn ref_from_raw(handle: *mut BNType) -> Ref<Self> {
489        debug_assert!(!handle.is_null());
490        Ref::new(Self { handle })
491    }
492
493    pub fn to_builder(&self) -> TypeBuilder {
494        TypeBuilder::new(self)
495    }
496
497    pub fn type_class(&self) -> TypeClass {
498        unsafe { BNGetTypeClass(self.handle) }
499    }
500
501    // TODO: We need to decide on a public type to represent type width.
502    // TODO: The api uses both `u64` and `usize`, pick one or a new type!
503    pub fn width(&self) -> u64 {
504        unsafe { BNGetTypeWidth(self.handle) }
505    }
506
507    pub fn alignment(&self) -> usize {
508        unsafe { BNGetTypeAlignment(self.handle) }
509    }
510
511    pub fn is_signed(&self) -> Conf<bool> {
512        unsafe { BNIsTypeSigned(self.handle).into() }
513    }
514
515    pub fn is_const(&self) -> Conf<bool> {
516        unsafe { BNIsTypeConst(self.handle).into() }
517    }
518
519    pub fn is_volatile(&self) -> Conf<bool> {
520        unsafe { BNIsTypeVolatile(self.handle).into() }
521    }
522
523    pub fn is_floating_point(&self) -> bool {
524        unsafe { BNIsTypeFloatingPoint(self.handle) }
525    }
526
527    pub fn child_type(&self) -> Option<Conf<Ref<Type>>> {
528        let raw_target = unsafe { BNGetChildType(self.handle) };
529        match raw_target.type_.is_null() {
530            false => Some(Conf::<Ref<Type>>::from_owned_raw(raw_target)),
531            true => None,
532        }
533    }
534
535    /// This is an alias for [`Self::child_type`].
536    pub fn target(&self) -> Option<Conf<Ref<Type>>> {
537        self.child_type()
538    }
539
540    /// This is an alias for [`Self::child_type`].
541    pub fn element_type(&self) -> Option<Conf<Ref<Type>>> {
542        self.child_type()
543    }
544
545    /// This is an alias for [`Self::child_type`].
546    pub fn return_value(&self) -> Option<Conf<Ref<Type>>> {
547        self.child_type()
548    }
549
550    pub fn calling_convention(&self) -> Option<Conf<Ref<CoreCallingConvention>>> {
551        let convention_confidence = unsafe { BNGetTypeCallingConvention(self.handle) };
552        match convention_confidence.convention.is_null() {
553            false => Some(Conf::<Ref<CoreCallingConvention>>::from_owned_raw(
554                convention_confidence,
555            )),
556            true => None,
557        }
558    }
559
560    pub fn parameters(&self) -> Option<Vec<FunctionParameter>> {
561        unsafe {
562            let mut count = 0;
563            let raw_parameters_ptr = BNGetTypeParameters(self.handle, &mut count);
564            match raw_parameters_ptr.is_null() {
565                false => {
566                    let raw_parameters = std::slice::from_raw_parts(raw_parameters_ptr, count);
567                    let parameters = raw_parameters
568                        .iter()
569                        .map(FunctionParameter::from_raw)
570                        .collect();
571                    BNFreeTypeParameterList(raw_parameters_ptr, count);
572                    Some(parameters)
573                }
574                true => None,
575            }
576        }
577    }
578
579    pub fn has_variable_arguments(&self) -> Conf<bool> {
580        unsafe { BNTypeHasVariableArguments(self.handle).into() }
581    }
582
583    pub fn can_return(&self) -> Conf<bool> {
584        unsafe { BNFunctionTypeCanReturn(self.handle).into() }
585    }
586
587    pub fn pure(&self) -> Conf<bool> {
588        unsafe { BNIsTypePure(self.handle).into() }
589    }
590
591    // TODO: This naming is problematic... rename to `as_structure`?
592    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
593    pub fn get_structure(&self) -> Option<Ref<Structure>> {
594        let raw_struct_ptr = unsafe { BNGetTypeStructure(self.handle) };
595        match raw_struct_ptr.is_null() {
596            false => Some(unsafe { Structure::ref_from_raw(raw_struct_ptr) }),
597            true => None,
598        }
599    }
600
601    // TODO: This naming is problematic... rename to `as_enumeration`?
602    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
603    pub fn get_enumeration(&self) -> Option<Ref<Enumeration>> {
604        let raw_enum_ptr = unsafe { BNGetTypeEnumeration(self.handle) };
605        match raw_enum_ptr.is_null() {
606            false => Some(unsafe { Enumeration::ref_from_raw(raw_enum_ptr) }),
607            true => None,
608        }
609    }
610
611    // TODO: This naming is problematic... rename to `as_named_type_reference`?
612    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
613    pub fn get_named_type_reference(&self) -> Option<Ref<NamedTypeReference>> {
614        let raw_type_ref_ptr = unsafe { BNGetTypeNamedTypeReference(self.handle) };
615        match raw_type_ref_ptr.is_null() {
616            false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
617            true => None,
618        }
619    }
620
621    pub fn count(&self) -> u64 {
622        unsafe { BNGetTypeElementCount(self.handle) }
623    }
624
625    pub fn offset(&self) -> u64 {
626        unsafe { BNGetTypeOffset(self.handle) }
627    }
628
629    pub fn stack_adjustment(&self) -> Conf<i64> {
630        unsafe { BNGetTypeStackAdjustment(self.handle).into() }
631    }
632
633    pub fn registered_name(&self) -> Option<Ref<NamedTypeReference>> {
634        let raw_type_ref_ptr = unsafe { BNGetRegisteredTypeName(self.handle) };
635        match raw_type_ref_ptr.is_null() {
636            false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
637            true => None,
638        }
639    }
640
641    pub fn pointer_base_type(&self) -> BNPointerBaseType {
642        unsafe { BNTypeGetPointerBaseType(self.handle) }
643    }
644
645    pub fn pointer_base_offset(&self) -> i64 {
646        unsafe { BNTypeGetPointerBaseOffset(self.handle) }
647    }
648
649    // TODO : This and properties
650    // pub fn tokens(&self) -> ? {}
651
652    pub fn void() -> Ref<Self> {
653        unsafe { Self::ref_from_raw(BNCreateVoidType()) }
654    }
655
656    pub fn bool() -> Ref<Self> {
657        unsafe { Self::ref_from_raw(BNCreateBoolType()) }
658    }
659
660    pub fn char() -> Ref<Self> {
661        Self::int(1, true)
662    }
663
664    pub fn wide_char(width: usize) -> Ref<Self> {
665        unsafe { Self::ref_from_raw(BNCreateWideCharType(width, c"".as_ptr())) }
666    }
667
668    pub fn int(width: usize, is_signed: bool) -> Ref<Self> {
669        let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
670        unsafe { Self::ref_from_raw(BNCreateIntegerType(width, &mut is_signed, c"".as_ptr())) }
671    }
672
673    pub fn named_int(width: usize, is_signed: bool, alt_name: &str) -> Ref<Self> {
674        let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
675        let alt_name = alt_name.to_cstr();
676
677        unsafe {
678            Self::ref_from_raw(BNCreateIntegerType(
679                width,
680                &mut is_signed,
681                alt_name.as_ptr(),
682            ))
683        }
684    }
685
686    pub fn float(width: usize) -> Ref<Self> {
687        unsafe { Self::ref_from_raw(BNCreateFloatType(width, c"".as_ptr())) }
688    }
689
690    pub fn named_float(width: usize, alt_name: &str) -> Ref<Self> {
691        let alt_name = alt_name.to_cstr();
692        unsafe { Self::ref_from_raw(BNCreateFloatType(width, alt_name.as_ptr())) }
693    }
694
695    pub fn array<'a, T: Into<Conf<&'a Type>>>(ty: T, count: u64) -> Ref<Self> {
696        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
697        unsafe { Self::ref_from_raw(BNCreateArrayType(&owned_raw_ty, count)) }
698    }
699
700    /// ## NOTE
701    ///
702    /// The C/C++ APIs require an associated architecture, but in the core we only query the default_int_size if the given width is 0.
703    ///
704    /// For simplicity's sake, that convention isn't followed, and you can query [`Architecture::default_integer_size`] if you need to.
705    pub fn enumeration<T: Into<Conf<bool>>>(
706        enumeration: &Enumeration,
707        width: NonZeroUsize,
708        is_signed: T,
709    ) -> Ref<Self> {
710        unsafe {
711            Self::ref_from_raw(BNCreateEnumerationType(
712                // TODO: We pass nullptr arch, really we should not even be passing arch.
713                std::ptr::null_mut(),
714                enumeration.handle,
715                width.get(),
716                &mut is_signed.into().into(),
717            ))
718        }
719    }
720
721    pub fn structure(structure: &Structure) -> Ref<Self> {
722        unsafe { Self::ref_from_raw(BNCreateStructureType(structure.handle)) }
723    }
724
725    pub fn named_type(type_reference: &NamedTypeReference) -> Ref<Self> {
726        let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
727        let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
728        unsafe {
729            Self::ref_from_raw(BNCreateNamedTypeReference(
730                type_reference.handle,
731                0,
732                1,
733                &mut is_const,
734                &mut is_volatile,
735            ))
736        }
737    }
738
739    pub fn named_type_from_type<T: Into<QualifiedName>>(name: T, t: &Type) -> Ref<Self> {
740        let mut raw_name = QualifiedName::into_raw(name.into());
741        // TODO: No id is present for this call?
742        let id = c"";
743
744        let result = unsafe {
745            Self::ref_from_raw(BNCreateNamedTypeReferenceFromTypeAndId(
746                id.as_ptr(),
747                &mut raw_name,
748                t.handle,
749            ))
750        };
751        QualifiedName::free_raw(raw_name);
752        result
753    }
754
755    // TODO: FunctionBuilder
756    pub fn function<'a, T: Into<Conf<&'a Type>>>(
757        return_type: T,
758        parameters: Vec<FunctionParameter>,
759        variable_arguments: bool,
760    ) -> Ref<Self> {
761        let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
762        let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
763        let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
764        let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
765
766        let mut raw_calling_convention: BNCallingConventionWithConfidence =
767            BNCallingConventionWithConfidence {
768                convention: std::ptr::null_mut(),
769                confidence: MIN_CONFIDENCE,
770            };
771
772        let mut stack_adjust = Conf::new(0, MIN_CONFIDENCE).into();
773        let mut raw_parameters = parameters
774            .into_iter()
775            .map(FunctionParameter::into_raw)
776            .collect::<Vec<_>>();
777        let reg_stack_adjust_regs = std::ptr::null_mut();
778        let reg_stack_adjust_values = std::ptr::null_mut();
779
780        let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
781            regs: std::ptr::null_mut(),
782            count: 0,
783            confidence: 0,
784        };
785
786        let result = unsafe {
787            Self::ref_from_raw(BNCreateFunctionType(
788                &mut owned_raw_return_type,
789                &mut raw_calling_convention,
790                raw_parameters.as_mut_ptr(),
791                raw_parameters.len(),
792                &mut variable_arguments,
793                &mut can_return,
794                &mut stack_adjust,
795                reg_stack_adjust_regs,
796                reg_stack_adjust_values,
797                0,
798                &mut return_regs,
799                BNNameType::NoNameType,
800                &mut pure,
801            ))
802        };
803
804        for raw_param in raw_parameters {
805            FunctionParameter::free_raw(raw_param);
806        }
807
808        result
809    }
810
811    // TODO: FunctionBuilder
812    pub fn function_with_opts<
813        'a,
814        T: Into<Conf<&'a Type>>,
815        C: Into<Conf<Ref<CoreCallingConvention>>>,
816    >(
817        return_type: T,
818        parameters: &[FunctionParameter],
819        variable_arguments: bool,
820        calling_convention: C,
821        stack_adjust: Conf<i64>,
822    ) -> Ref<Self> {
823        let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
824        let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
825        let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
826        let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
827
828        let mut owned_raw_calling_convention =
829            Conf::<Ref<CoreCallingConvention>>::into_owned_raw(&calling_convention.into());
830
831        let mut stack_adjust = stack_adjust.into();
832        let mut raw_parameters = parameters
833            .iter()
834            .cloned()
835            .map(FunctionParameter::into_raw)
836            .collect::<Vec<_>>();
837
838        // TODO: Update type signature and include these (will be a breaking change)
839        let reg_stack_adjust_regs = std::ptr::null_mut();
840        let reg_stack_adjust_values = std::ptr::null_mut();
841
842        let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
843            regs: std::ptr::null_mut(),
844            count: 0,
845            confidence: 0,
846        };
847
848        let result = unsafe {
849            Self::ref_from_raw(BNCreateFunctionType(
850                &mut owned_raw_return_type,
851                &mut owned_raw_calling_convention,
852                raw_parameters.as_mut_ptr(),
853                raw_parameters.len(),
854                &mut variable_arguments,
855                &mut can_return,
856                &mut stack_adjust,
857                reg_stack_adjust_regs,
858                reg_stack_adjust_values,
859                0,
860                &mut return_regs,
861                BNNameType::NoNameType,
862                &mut pure,
863            ))
864        };
865
866        for raw_param in raw_parameters {
867            FunctionParameter::free_raw(raw_param);
868        }
869
870        result
871    }
872
873    pub fn pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Ref<Self> {
874        let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
875        let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
876        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
877        unsafe {
878            Self::ref_from_raw(BNCreatePointerType(
879                arch.as_ref().handle,
880                &owned_raw_ty,
881                &mut is_const,
882                &mut is_volatile,
883                ReferenceType::PointerReferenceType,
884            ))
885        }
886    }
887
888    pub fn const_pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
889        arch: &A,
890        ty: T,
891    ) -> Ref<Self> {
892        let mut is_const = Conf::new(true, MAX_CONFIDENCE).into();
893        let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
894        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
895        unsafe {
896            Self::ref_from_raw(BNCreatePointerType(
897                arch.as_ref().handle,
898                &owned_raw_ty,
899                &mut is_const,
900                &mut is_volatile,
901                ReferenceType::PointerReferenceType,
902            ))
903        }
904    }
905
906    pub fn pointer_of_width<'a, T: Into<Conf<&'a Type>>>(
907        ty: T,
908        size: usize,
909        is_const: bool,
910        is_volatile: bool,
911        ref_type: Option<ReferenceType>,
912    ) -> Ref<Self> {
913        let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
914        let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
915        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
916        unsafe {
917            Self::ref_from_raw(BNCreatePointerTypeOfWidth(
918                size,
919                &owned_raw_ty,
920                &mut is_const,
921                &mut is_volatile,
922                ref_type.unwrap_or(ReferenceType::PointerReferenceType),
923            ))
924        }
925    }
926
927    pub fn pointer_with_options<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
928        arch: &A,
929        ty: T,
930        is_const: bool,
931        is_volatile: bool,
932        ref_type: Option<ReferenceType>,
933    ) -> Ref<Self> {
934        let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
935        let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
936        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
937        unsafe {
938            Self::ref_from_raw(BNCreatePointerType(
939                arch.as_ref().handle,
940                &owned_raw_ty,
941                &mut is_const,
942                &mut is_volatile,
943                ref_type.unwrap_or(ReferenceType::PointerReferenceType),
944            ))
945        }
946    }
947
948    pub fn generate_auto_demangled_type_id<T: Into<QualifiedName>>(name: T) -> String {
949        let mut raw_name = QualifiedName::into_raw(name.into());
950        let type_id =
951            unsafe { BnString::into_string(BNGenerateAutoDemangledTypeId(&mut raw_name)) };
952        QualifiedName::free_raw(raw_name);
953        type_id
954    }
955}
956
957impl Display for Type {
958    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
959        write!(f, "{}", unsafe {
960            BnString::into_string(BNGetTypeString(
961                self.handle,
962                std::ptr::null_mut(),
963                BNTokenEscapingType::NoTokenEscapingType,
964            ))
965        })
966    }
967}
968
969impl Debug for Type {
970    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
971        // You might be tempted to rip this atrocity out and make this more "sensible". READ BELOW!
972        // Type is a one-size fits all structure, these are actually its fields! If we wanted to
973        // omit some fields for different type classes what you really want to do is implement your
974        // own formatter. This is supposed to represent the structure entirely, it's not supposed to be pretty!
975        f.debug_struct("Type")
976            .field("type_class", &self.type_class())
977            .field("width", &self.width())
978            .field("alignment", &self.alignment())
979            .field("is_signed", &self.is_signed())
980            .field("is_const", &self.is_const())
981            .field("is_volatile", &self.is_volatile())
982            .field("child_type", &self.child_type())
983            .field("calling_convention", &self.calling_convention())
984            .field("parameters", &self.parameters())
985            .field("has_variable_arguments", &self.has_variable_arguments())
986            .field("can_return", &self.can_return())
987            .field("pure", &self.pure())
988            .field("get_structure", &self.get_structure())
989            .field("get_enumeration", &self.get_enumeration())
990            .field("get_named_type_reference", &self.get_named_type_reference())
991            .field("count", &self.count())
992            .field("offset", &self.offset())
993            .field("stack_adjustment", &self.stack_adjustment())
994            .field("registered_name", &self.registered_name())
995            .finish()
996    }
997}
998
999impl PartialEq for Type {
1000    fn eq(&self, other: &Self) -> bool {
1001        unsafe { BNTypesEqual(self.handle, other.handle) }
1002    }
1003}
1004
1005impl Eq for Type {}
1006
1007impl Hash for Type {
1008    fn hash<H: Hasher>(&self, state: &mut H) {
1009        self.handle.hash(state);
1010    }
1011}
1012
1013unsafe impl Send for Type {}
1014unsafe impl Sync for Type {}
1015
1016unsafe impl RefCountable for Type {
1017    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
1018        Self::ref_from_raw(BNNewTypeReference(handle.handle))
1019    }
1020
1021    unsafe fn dec_ref(handle: &Self) {
1022        BNFreeType(handle.handle);
1023    }
1024}
1025
1026impl ToOwned for Type {
1027    type Owned = Ref<Self>;
1028
1029    fn to_owned(&self) -> Self::Owned {
1030        unsafe { RefCountable::inc_ref(self) }
1031    }
1032}
1033
1034impl CoreArrayProvider for Type {
1035    type Raw = *mut BNType;
1036    type Context = ();
1037    type Wrapped<'a> = &'a Self;
1038}
1039
1040unsafe impl CoreArrayProviderInner for Type {
1041    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
1042        BNFreeTypeList(raw, count)
1043    }
1044
1045    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
1046        // TODO: This is assuming &'a Type is &*mut BNType
1047        std::mem::transmute(raw)
1048    }
1049}
1050
1051// TODO: Remove this struct, or make it not a ZST with a terrible array provider.
1052/// ZST used only for `Array<ComponentReferencedType>`.
1053pub struct ComponentReferencedType;
1054
1055impl CoreArrayProvider for ComponentReferencedType {
1056    type Raw = *mut BNType;
1057    type Context = ();
1058    type Wrapped<'a> = &'a Type;
1059}
1060
1061unsafe impl CoreArrayProviderInner for ComponentReferencedType {
1062    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
1063        BNComponentFreeReferencedTypes(raw, count)
1064    }
1065
1066    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
1067        // SAFETY: &*mut BNType == &Type (*mut BNType == Type)
1068        std::mem::transmute(raw)
1069    }
1070}
1071
1072#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1073pub struct FunctionParameter {
1074    pub ty: Conf<Ref<Type>>,
1075    pub name: String,
1076    pub location: Option<Variable>,
1077}
1078
1079impl FunctionParameter {
1080    pub(crate) fn from_raw(value: &BNFunctionParameter) -> Self {
1081        // TODO: I copied this from the original `from_raw` function.
1082        // TODO: So this actually needs to be audited later.
1083        let name = if value.name.is_null() {
1084            if value.location.type_ == VariableSourceType::RegisterVariableSourceType {
1085                format!("reg_{}", value.location.storage)
1086            } else if value.location.type_ == VariableSourceType::StackVariableSourceType {
1087                format!("arg_{}", value.location.storage)
1088            } else {
1089                String::new()
1090            }
1091        } else {
1092            raw_to_string(value.name as *const _).unwrap()
1093        };
1094
1095        Self {
1096            ty: Conf::new(
1097                unsafe { Type::from_raw(value.type_).to_owned() },
1098                value.typeConfidence,
1099            ),
1100            name,
1101            location: match value.defaultLocation {
1102                false => Some(Variable::from(value.location)),
1103                true => None,
1104            },
1105        }
1106    }
1107
1108    pub(crate) fn from_owned_raw(value: BNFunctionParameter) -> Self {
1109        let owned = Self::from_raw(&value);
1110        Self::free_raw(value);
1111        owned
1112    }
1113
1114    pub(crate) fn into_raw(value: Self) -> BNFunctionParameter {
1115        let bn_name = BnString::new(value.name);
1116        BNFunctionParameter {
1117            name: BnString::into_raw(bn_name),
1118            type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
1119            typeConfidence: value.ty.confidence,
1120            defaultLocation: value.location.is_none(),
1121            location: value.location.map(Into::into).unwrap_or_default(),
1122        }
1123    }
1124
1125    pub(crate) fn free_raw(value: BNFunctionParameter) {
1126        unsafe { BnString::free_raw(value.name) };
1127        let _ = unsafe { Type::ref_from_raw(value.type_) };
1128    }
1129
1130    pub fn new<T: Into<Conf<Ref<Type>>>>(ty: T, name: String, location: Option<Variable>) -> Self {
1131        Self {
1132            ty: ty.into(),
1133            name,
1134            location,
1135        }
1136    }
1137}
1138
1139#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1140pub struct EnumerationMember {
1141    pub name: String,
1142    /// The associated constant value for the member.
1143    pub value: u64,
1144    /// Whether this is the default member for the associated [`Enumeration`].
1145    pub default: bool,
1146}
1147
1148impl EnumerationMember {
1149    pub(crate) fn from_raw(value: &BNEnumerationMember) -> Self {
1150        Self {
1151            name: raw_to_string(value.name).unwrap(),
1152            value: value.value,
1153            default: value.isDefault,
1154        }
1155    }
1156
1157    pub(crate) fn from_owned_raw(value: BNEnumerationMember) -> Self {
1158        let owned = Self::from_raw(&value);
1159        Self::free_raw(value);
1160        owned
1161    }
1162
1163    pub(crate) fn into_raw(value: Self) -> BNEnumerationMember {
1164        let bn_name = BnString::new(value.name);
1165        BNEnumerationMember {
1166            name: BnString::into_raw(bn_name),
1167            value: value.value,
1168            isDefault: value.default,
1169        }
1170    }
1171
1172    pub(crate) fn free_raw(value: BNEnumerationMember) {
1173        unsafe { BnString::free_raw(value.name) };
1174    }
1175
1176    pub fn new(name: String, value: u64, default: bool) -> Self {
1177        Self {
1178            name,
1179            value,
1180            default,
1181        }
1182    }
1183}
1184
1185#[derive(PartialEq, Eq, Hash)]
1186pub struct EnumerationBuilder {
1187    pub(crate) handle: *mut BNEnumerationBuilder,
1188}
1189
1190impl EnumerationBuilder {
1191    pub fn new() -> Self {
1192        Self {
1193            handle: unsafe { BNCreateEnumerationBuilder() },
1194        }
1195    }
1196
1197    pub(crate) unsafe fn from_raw(handle: *mut BNEnumerationBuilder) -> Self {
1198        Self { handle }
1199    }
1200
1201    pub fn finalize(&self) -> Ref<Enumeration> {
1202        unsafe { Enumeration::ref_from_raw(BNFinalizeEnumerationBuilder(self.handle)) }
1203    }
1204
1205    pub fn append(&mut self, name: &str) -> &mut Self {
1206        let name = name.to_cstr();
1207        unsafe {
1208            BNAddEnumerationBuilderMember(self.handle, name.as_ref().as_ptr() as _);
1209        }
1210        self
1211    }
1212
1213    pub fn insert(&mut self, name: &str, value: u64) -> &mut Self {
1214        let name = name.to_cstr();
1215        unsafe {
1216            BNAddEnumerationBuilderMemberWithValue(self.handle, name.as_ref().as_ptr() as _, value);
1217        }
1218        self
1219    }
1220
1221    pub fn replace(&mut self, id: usize, name: &str, value: u64) -> &mut Self {
1222        let name = name.to_cstr();
1223        unsafe {
1224            BNReplaceEnumerationBuilderMember(self.handle, id, name.as_ref().as_ptr() as _, value);
1225        }
1226        self
1227    }
1228
1229    pub fn remove(&mut self, id: usize) -> &mut Self {
1230        unsafe {
1231            BNRemoveEnumerationBuilderMember(self.handle, id);
1232        }
1233
1234        self
1235    }
1236
1237    pub fn members(&self) -> Vec<EnumerationMember> {
1238        unsafe {
1239            let mut count = 0;
1240            let members_raw_ptr = BNGetEnumerationBuilderMembers(self.handle, &mut count);
1241            let members_raw: &[BNEnumerationMember] =
1242                std::slice::from_raw_parts(members_raw_ptr, count);
1243            let members = members_raw
1244                .iter()
1245                .map(EnumerationMember::from_raw)
1246                .collect();
1247            BNFreeEnumerationMemberList(members_raw_ptr, count);
1248            members
1249        }
1250    }
1251}
1252
1253impl Default for EnumerationBuilder {
1254    fn default() -> Self {
1255        Self::new()
1256    }
1257}
1258
1259impl From<&Enumeration> for EnumerationBuilder {
1260    fn from(enumeration: &Enumeration) -> Self {
1261        unsafe {
1262            Self::from_raw(BNCreateEnumerationBuilderFromEnumeration(
1263                enumeration.handle,
1264            ))
1265        }
1266    }
1267}
1268
1269impl Drop for EnumerationBuilder {
1270    fn drop(&mut self) {
1271        unsafe { BNFreeEnumerationBuilder(self.handle) };
1272    }
1273}
1274
1275#[derive(PartialEq, Eq, Hash)]
1276pub struct Enumeration {
1277    pub(crate) handle: *mut BNEnumeration,
1278}
1279
1280impl Enumeration {
1281    pub(crate) unsafe fn ref_from_raw(handle: *mut BNEnumeration) -> Ref<Self> {
1282        debug_assert!(!handle.is_null());
1283        Ref::new(Self { handle })
1284    }
1285
1286    pub fn builder() -> EnumerationBuilder {
1287        EnumerationBuilder::new()
1288    }
1289
1290    pub fn members(&self) -> Vec<EnumerationMember> {
1291        unsafe {
1292            let mut count = 0;
1293            let members_raw_ptr = BNGetEnumerationMembers(self.handle, &mut count);
1294            debug_assert!(!members_raw_ptr.is_null());
1295            let members_raw: &[BNEnumerationMember] =
1296                std::slice::from_raw_parts(members_raw_ptr, count);
1297            let members = members_raw
1298                .iter()
1299                .map(EnumerationMember::from_raw)
1300                .collect();
1301            BNFreeEnumerationMemberList(members_raw_ptr, count);
1302            members
1303        }
1304    }
1305}
1306
1307impl Debug for Enumeration {
1308    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1309        f.debug_struct("Enumeration")
1310            .field("members", &self.members())
1311            .finish()
1312    }
1313}
1314
1315unsafe impl RefCountable for Enumeration {
1316    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
1317        Self::ref_from_raw(BNNewEnumerationReference(handle.handle))
1318    }
1319
1320    unsafe fn dec_ref(handle: &Self) {
1321        BNFreeEnumeration(handle.handle);
1322    }
1323}
1324
1325impl ToOwned for Enumeration {
1326    type Owned = Ref<Self>;
1327
1328    fn to_owned(&self) -> Self::Owned {
1329        unsafe { RefCountable::inc_ref(self) }
1330    }
1331}
1332
1333#[derive(PartialEq, Eq, Hash)]
1334pub struct StructureBuilder {
1335    pub(crate) handle: *mut BNStructureBuilder,
1336}
1337
1338/// ```no_run
1339/// // Includes
1340/// # use binaryninja::binary_view::BinaryViewExt;
1341/// use binaryninja::types::{MemberAccess, MemberScope, Structure, StructureBuilder, Type};
1342///
1343/// // Types to use in the members
1344/// let field_1_ty = Type::named_int(5, false, "my_weird_int_type");
1345/// let field_2_ty = Type::int(4, false);
1346/// let field_3_ty = Type::int(8, false);
1347///
1348/// // Assign those fields
1349/// let mut my_custom_struct = StructureBuilder::new();
1350/// my_custom_struct
1351///     .insert(
1352///         &field_1_ty,
1353///         "field_1",
1354///         0,
1355///         false,
1356///         MemberAccess::PublicAccess,
1357///         MemberScope::NoScope,
1358///     )
1359///     .insert(
1360///         &field_2_ty,
1361///         "field_2",
1362///         5,
1363///         false,
1364///         MemberAccess::PublicAccess,
1365///         MemberScope::NoScope,
1366///     )
1367///     .insert(
1368///         &field_3_ty,
1369///         "field_3",
1370///         9,
1371///         false,
1372///         MemberAccess::PublicAccess,
1373///         MemberScope::NoScope,
1374///     )
1375///     .append(
1376///         &field_1_ty,
1377///         "field_4",
1378///         MemberAccess::PublicAccess,
1379///         MemberScope::NoScope,
1380///     );
1381///
1382/// // Convert structure to type
1383/// let my_custom_structure_type = Type::structure(&my_custom_struct.finalize());
1384///
1385/// // Add the struct to the binary view to use in analysis
1386/// let bv = binaryninja::load("example").unwrap();
1387/// bv.define_user_type("my_custom_struct", &my_custom_structure_type);
1388/// ```
1389impl StructureBuilder {
1390    pub fn new() -> Self {
1391        Self {
1392            handle: unsafe { BNCreateStructureBuilder() },
1393        }
1394    }
1395
1396    pub(crate) unsafe fn from_raw(handle: *mut BNStructureBuilder) -> Self {
1397        debug_assert!(!handle.is_null());
1398        Self { handle }
1399    }
1400
1401    // TODO: Document the width adjustment with alignment.
1402    pub fn finalize(&self) -> Ref<Structure> {
1403        let raw_struct_ptr = unsafe { BNFinalizeStructureBuilder(self.handle) };
1404        unsafe { Structure::ref_from_raw(raw_struct_ptr) }
1405    }
1406
1407    /// Sets the width of the [`StructureBuilder`] to the new width.
1408    ///
1409    /// This will remove all previously inserted members outside the new width. This is done by computing
1410    /// the member access range (member offset + member width) and if it is larger than the new width
1411    /// it will be removed.
1412    pub fn width(&mut self, width: u64) -> &mut Self {
1413        unsafe {
1414            BNSetStructureBuilderWidth(self.handle, width);
1415        }
1416        self
1417    }
1418
1419    pub fn alignment(&mut self, alignment: usize) -> &mut Self {
1420        unsafe {
1421            BNSetStructureBuilderAlignment(self.handle, alignment);
1422        }
1423        self
1424    }
1425
1426    /// Sets whether the [`StructureBuilder`] is packed.
1427    ///
1428    /// If set the alignment of the structure will be `1`. You do not need to set the alignment to `1`.
1429    pub fn packed(&mut self, packed: bool) -> &mut Self {
1430        unsafe {
1431            BNSetStructureBuilderPacked(self.handle, packed);
1432        }
1433        self
1434    }
1435
1436    pub fn structure_type(&mut self, t: StructureType) -> &mut Self {
1437        unsafe { BNSetStructureBuilderType(self.handle, t) };
1438        self
1439    }
1440
1441    pub fn pointer_offset(&mut self, offset: i64) -> &mut Self {
1442        unsafe { BNSetStructureBuilderPointerOffset(self.handle, offset) };
1443        self
1444    }
1445
1446    pub fn propagates_data_var_refs(&mut self, propagates: bool) -> &mut Self {
1447        unsafe { BNSetStructureBuilderPropagatesDataVariableReferences(self.handle, propagates) };
1448        self
1449    }
1450
1451    pub fn base_structures(&mut self, bases: &[BaseStructure]) -> &mut Self {
1452        let raw_base_structs: Vec<BNBaseStructure> =
1453            bases.iter().map(BaseStructure::into_owned_raw).collect();
1454        unsafe {
1455            BNSetBaseStructuresForStructureBuilder(
1456                self.handle,
1457                raw_base_structs.as_ptr() as *mut _,
1458                raw_base_structs.len(),
1459            )
1460        };
1461        self
1462    }
1463
1464    /// Append a member at the next available byte offset.
1465    ///
1466    /// Otherwise, consider using:
1467    ///
1468    /// - [`StructureBuilder::insert_member`]
1469    /// - [`StructureBuilder::insert`]
1470    /// - [`StructureBuilder::insert_bitwise`]
1471    pub fn append<'a, T: Into<Conf<&'a Type>>>(
1472        &mut self,
1473        ty: T,
1474        name: &str,
1475        access: MemberAccess,
1476        scope: MemberScope,
1477    ) -> &mut Self {
1478        let name = name.to_cstr();
1479        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
1480        unsafe {
1481            BNAddStructureBuilderMember(
1482                self.handle,
1483                &owned_raw_ty,
1484                name.as_ref().as_ptr() as _,
1485                access,
1486                scope,
1487            );
1488        }
1489        self
1490    }
1491
1492    /// Insert an already constructed [`StructureMember`].
1493    ///
1494    /// Otherwise, consider using:
1495    ///
1496    /// - [`StructureBuilder::append`]
1497    /// - [`StructureBuilder::insert`]
1498    /// - [`StructureBuilder::insert_bitwise`]
1499    pub fn insert_member(
1500        &mut self,
1501        member: StructureMember,
1502        overwrite_existing: bool,
1503    ) -> &mut Self {
1504        self.insert_bitwise(
1505            &member.ty,
1506            &member.name,
1507            member.bit_offset(),
1508            member.bit_width,
1509            overwrite_existing,
1510            member.access,
1511            member.scope,
1512        );
1513        self
1514    }
1515
1516    /// Inserts a member at the `offset` (in bytes).
1517    ///
1518    /// If you need to insert a member at a specific bit within a given byte (like a bitfield), you
1519    /// can use [`StructureBuilder::insert_bitwise`].
1520    pub fn insert<'a, T: Into<Conf<&'a Type>>>(
1521        &mut self,
1522        ty: T,
1523        name: &str,
1524        offset: u64,
1525        overwrite_existing: bool,
1526        access: MemberAccess,
1527        scope: MemberScope,
1528    ) -> &mut Self {
1529        self.insert_bitwise(
1530            ty,
1531            name,
1532            offset * 8,
1533            None,
1534            overwrite_existing,
1535            access,
1536            scope,
1537        )
1538    }
1539
1540    /// Inserts a member at `bit_offset` with an optional `bit_width`.
1541    ///
1542    /// NOTE: The `bit_offset` is relative to the start of the structure, for example, passing `8` will place
1543    /// the field at the start of the byte `0x1`.
1544    pub fn insert_bitwise<'a, T: Into<Conf<&'a Type>>>(
1545        &mut self,
1546        ty: T,
1547        name: &str,
1548        bit_offset: u64,
1549        bit_width: Option<u8>,
1550        overwrite_existing: bool,
1551        access: MemberAccess,
1552        scope: MemberScope,
1553    ) -> &mut Self {
1554        let name = name.to_cstr();
1555        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
1556        let byte_offset = bit_offset / 8;
1557        let bit_position = bit_offset % 8;
1558        unsafe {
1559            BNAddStructureBuilderMemberAtOffset(
1560                self.handle,
1561                &owned_raw_ty,
1562                name.as_ref().as_ptr() as _,
1563                byte_offset,
1564                overwrite_existing,
1565                access,
1566                scope,
1567                bit_position as u8,
1568                bit_width.unwrap_or(0),
1569            );
1570        }
1571        self
1572    }
1573
1574    pub fn replace<'a, T: Into<Conf<&'a Type>>>(
1575        &mut self,
1576        index: usize,
1577        ty: T,
1578        name: &str,
1579        overwrite_existing: bool,
1580    ) -> &mut Self {
1581        let name = name.to_cstr();
1582        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
1583        unsafe {
1584            BNReplaceStructureBuilderMember(
1585                self.handle,
1586                index,
1587                &owned_raw_ty,
1588                name.as_ref().as_ptr() as _,
1589                overwrite_existing,
1590            )
1591        }
1592        self
1593    }
1594
1595    /// Removes the member at a given index.
1596    pub fn remove(&mut self, index: usize) -> &mut Self {
1597        unsafe { BNRemoveStructureBuilderMember(self.handle, index) };
1598        self
1599    }
1600
1601    // TODO: We should add BNGetStructureBuilderAlignedWidth
1602    /// Gets the current **unaligned** width of the structure.
1603    ///
1604    /// This cannot be used to accurately get the width of a non-packed structure.
1605    pub fn current_width(&self) -> u64 {
1606        unsafe { BNGetStructureBuilderWidth(self.handle) }
1607    }
1608}
1609
1610impl From<&Structure> for StructureBuilder {
1611    fn from(structure: &Structure) -> StructureBuilder {
1612        unsafe { Self::from_raw(BNCreateStructureBuilderFromStructure(structure.handle)) }
1613    }
1614}
1615
1616impl From<Vec<StructureMember>> for StructureBuilder {
1617    fn from(members: Vec<StructureMember>) -> StructureBuilder {
1618        let mut builder = StructureBuilder::new();
1619        for member in members {
1620            builder.insert_member(member, false);
1621        }
1622        builder
1623    }
1624}
1625
1626impl Drop for StructureBuilder {
1627    fn drop(&mut self) {
1628        unsafe { BNFreeStructureBuilder(self.handle) };
1629    }
1630}
1631
1632impl Default for StructureBuilder {
1633    fn default() -> Self {
1634        Self::new()
1635    }
1636}
1637
1638#[derive(PartialEq, Eq, Hash)]
1639pub struct Structure {
1640    pub(crate) handle: *mut BNStructure,
1641}
1642
1643impl Structure {
1644    pub(crate) unsafe fn ref_from_raw(handle: *mut BNStructure) -> Ref<Self> {
1645        debug_assert!(!handle.is_null());
1646        Ref::new(Self { handle })
1647    }
1648
1649    pub fn builder() -> StructureBuilder {
1650        StructureBuilder::new()
1651    }
1652
1653    pub fn width(&self) -> u64 {
1654        unsafe { BNGetStructureWidth(self.handle) }
1655    }
1656
1657    pub fn structure_type(&self) -> StructureType {
1658        unsafe { BNGetStructureType(self.handle) }
1659    }
1660
1661    /// Retrieve the members that are accessible at a given offset.
1662    ///
1663    /// The reason for this being plural is that members may overlap and the offset is in bytes
1664    /// where a bitfield may contain multiple members at the given byte.
1665    ///
1666    /// Unions are also represented as structures and will cause this function to return
1667    /// **all** members that can reach that offset.
1668    ///
1669    /// We must pass a [`TypeContainer`] here so that we can resolve base structure members, as they
1670    /// are treated as members through this function. Typically, you get the [`TypeContainer`]
1671    /// through the binary view with [`BinaryViewExt::type_container`].
1672    pub fn members_at_offset(
1673        &self,
1674        container: &TypeContainer,
1675        offset: u64,
1676    ) -> Vec<StructureMember> {
1677        self.members_including_inherited(container)
1678            .into_iter()
1679            .filter(|m| m.member.is_offset_valid(offset))
1680            .map(|m| m.member)
1681            .collect()
1682    }
1683
1684    /// Return the list of non-inherited structure members.
1685    ///
1686    /// If you want to get all members, including ones inherited from base structures,
1687    /// use [`Structure::members_including_inherited`] instead.
1688    pub fn members(&self) -> Vec<StructureMember> {
1689        unsafe {
1690            let mut count = 0;
1691            let members_raw_ptr: *mut BNStructureMember =
1692                BNGetStructureMembers(self.handle, &mut count);
1693            debug_assert!(!members_raw_ptr.is_null());
1694            let members_raw = std::slice::from_raw_parts(members_raw_ptr, count);
1695            let members = members_raw.iter().map(StructureMember::from_raw).collect();
1696            BNFreeStructureMemberList(members_raw_ptr, count);
1697            members
1698        }
1699    }
1700
1701    /// Returns the list of all structure members, including inherited ones.
1702    ///
1703    /// Because we must traverse through base structures, we have to provide the [`TypeContainer`];
1704    /// in most cases it is ok to provide the binary views container via [`BinaryViewExt::type_container`].
1705    pub fn members_including_inherited(
1706        &self,
1707        container: &TypeContainer,
1708    ) -> Vec<InheritedStructureMember> {
1709        unsafe {
1710            let mut count = 0;
1711            let members_raw_ptr: *mut BNInheritedStructureMember =
1712                BNGetStructureMembersIncludingInherited(
1713                    self.handle,
1714                    container.handle.as_ptr(),
1715                    &mut count,
1716                );
1717            debug_assert!(!members_raw_ptr.is_null());
1718            let members_raw = std::slice::from_raw_parts(members_raw_ptr, count);
1719            let members = members_raw
1720                .iter()
1721                .map(InheritedStructureMember::from_raw)
1722                .collect();
1723            BNFreeInheritedStructureMemberList(members_raw_ptr, count);
1724            members
1725        }
1726    }
1727
1728    /// Retrieve the list of base structures for the structure. These base structures are what give
1729    /// a structure inherited members.
1730    pub fn base_structures(&self) -> Vec<BaseStructure> {
1731        let mut count = 0;
1732        let bases_raw_ptr = unsafe { BNGetBaseStructuresForStructure(self.handle, &mut count) };
1733        debug_assert!(!bases_raw_ptr.is_null());
1734        let bases_raw = unsafe { std::slice::from_raw_parts(bases_raw_ptr, count) };
1735        let bases = bases_raw.iter().map(BaseStructure::from_raw).collect();
1736        unsafe { BNFreeBaseStructureList(bases_raw_ptr, count) };
1737        bases
1738    }
1739
1740    /// Whether the structure is packed or not.
1741    pub fn is_packed(&self) -> bool {
1742        unsafe { BNIsStructurePacked(self.handle) }
1743    }
1744
1745    pub fn alignment(&self) -> usize {
1746        unsafe { BNGetStructureAlignment(self.handle) }
1747    }
1748}
1749
1750impl Debug for Structure {
1751    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1752        f.debug_struct("Structure")
1753            .field("width", &self.width())
1754            .field("alignment", &self.alignment())
1755            .field("packed", &self.is_packed())
1756            .field("structure_type", &self.structure_type())
1757            .field("base_structures", &self.base_structures())
1758            .field("members", &self.members())
1759            .finish()
1760    }
1761}
1762
1763unsafe impl RefCountable for Structure {
1764    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
1765        Self::ref_from_raw(BNNewStructureReference(handle.handle))
1766    }
1767
1768    unsafe fn dec_ref(handle: &Self) {
1769        BNFreeStructure(handle.handle);
1770    }
1771}
1772
1773impl ToOwned for Structure {
1774    type Owned = Ref<Self>;
1775
1776    fn to_owned(&self) -> Self::Owned {
1777        unsafe { RefCountable::inc_ref(self) }
1778    }
1779}
1780
1781#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1782pub struct StructureMember {
1783    pub ty: Conf<Ref<Type>>,
1784    // TODO: Shouldnt this be a QualifiedName? The ffi says no...
1785    pub name: String,
1786    /// The byte offset of the member.
1787    pub offset: u64,
1788    pub access: MemberAccess,
1789    pub scope: MemberScope,
1790    /// The bit position relative to the byte offset.
1791    pub bit_position: Option<u8>,
1792    pub bit_width: Option<u8>,
1793}
1794
1795impl StructureMember {
1796    pub(crate) fn from_raw(value: &BNStructureMember) -> Self {
1797        Self {
1798            ty: Conf::new(
1799                unsafe { Type::from_raw(value.type_) }.to_owned(),
1800                value.typeConfidence,
1801            ),
1802            // TODO: I dislike using this function here.
1803            name: raw_to_string(value.name as *mut _).unwrap(),
1804            offset: value.offset,
1805            access: value.access,
1806            scope: value.scope,
1807            bit_position: match value.bitPosition {
1808                0 => None,
1809                _ => Some(value.bitPosition),
1810            },
1811            bit_width: match value.bitWidth {
1812                0 => None,
1813                _ => Some(value.bitWidth),
1814            },
1815        }
1816    }
1817
1818    pub(crate) fn from_owned_raw(value: BNStructureMember) -> Self {
1819        let owned = Self::from_raw(&value);
1820        Self::free_raw(value);
1821        owned
1822    }
1823
1824    pub(crate) fn into_raw(value: Self) -> BNStructureMember {
1825        let bn_name = BnString::new(value.name);
1826        BNStructureMember {
1827            type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
1828            name: BnString::into_raw(bn_name),
1829            offset: value.offset,
1830            typeConfidence: value.ty.confidence,
1831            access: value.access,
1832            scope: value.scope,
1833            bitPosition: value.bit_position.unwrap_or(0),
1834            bitWidth: value.bit_width.unwrap_or(0),
1835        }
1836    }
1837
1838    pub(crate) fn free_raw(value: BNStructureMember) {
1839        let _ = unsafe { Type::ref_from_raw(value.type_) };
1840        unsafe { BnString::free_raw(value.name) };
1841    }
1842
1843    pub fn new(
1844        ty: Conf<Ref<Type>>,
1845        name: String,
1846        offset: u64,
1847        access: MemberAccess,
1848        scope: MemberScope,
1849    ) -> Self {
1850        Self {
1851            ty,
1852            name,
1853            offset,
1854            access,
1855            scope,
1856            bit_position: None,
1857            bit_width: None,
1858        }
1859    }
1860
1861    pub fn new_bitfield(
1862        ty: Conf<Ref<Type>>,
1863        name: String,
1864        bit_offset: u64,
1865        bit_width: u8,
1866        access: MemberAccess,
1867        scope: MemberScope,
1868    ) -> Self {
1869        Self {
1870            ty,
1871            name,
1872            offset: bit_offset / 8,
1873            access,
1874            scope,
1875            bit_position: Some((bit_offset % 8) as u8),
1876            bit_width: Some(bit_width),
1877        }
1878    }
1879
1880    // TODO: Do we count bitwidth here?
1881    /// Whether the offset within the accessible range of the member.
1882    pub fn is_offset_valid(&self, offset: u64) -> bool {
1883        self.offset <= offset && offset < self.offset + self.ty.contents.width()
1884    }
1885
1886    /// Member offset in bits.
1887    pub fn bit_offset(&self) -> u64 {
1888        (self.offset * 8) + self.bit_position.unwrap_or(0) as u64
1889    }
1890}
1891
1892impl CoreArrayProvider for StructureMember {
1893    type Raw = BNStructureMember;
1894    type Context = ();
1895    type Wrapped<'a> = Self;
1896}
1897
1898unsafe impl CoreArrayProviderInner for StructureMember {
1899    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
1900        BNFreeStructureMemberList(raw, count)
1901    }
1902
1903    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
1904        Self::from_raw(raw)
1905    }
1906}
1907
1908#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1909pub struct InheritedStructureMember {
1910    pub base: Ref<NamedTypeReference>,
1911    pub base_offset: u64,
1912    pub member: StructureMember,
1913    pub member_index: usize,
1914}
1915
1916impl InheritedStructureMember {
1917    pub(crate) fn from_raw(value: &BNInheritedStructureMember) -> Self {
1918        Self {
1919            base: unsafe { NamedTypeReference::from_raw(value.base) }.to_owned(),
1920            base_offset: value.baseOffset,
1921            member: StructureMember::from_raw(&value.member),
1922            member_index: value.memberIndex,
1923        }
1924    }
1925
1926    pub(crate) fn from_owned_raw(value: BNInheritedStructureMember) -> Self {
1927        let owned = Self::from_raw(&value);
1928        Self::free_raw(value);
1929        owned
1930    }
1931
1932    pub(crate) fn into_raw(value: Self) -> BNInheritedStructureMember {
1933        BNInheritedStructureMember {
1934            base: unsafe { Ref::into_raw(value.base) }.handle,
1935            baseOffset: value.base_offset,
1936            member: StructureMember::into_raw(value.member),
1937            memberIndex: value.member_index,
1938        }
1939    }
1940
1941    pub(crate) fn free_raw(value: BNInheritedStructureMember) {
1942        let _ = unsafe { NamedTypeReference::ref_from_raw(value.base) };
1943        StructureMember::free_raw(value.member);
1944    }
1945
1946    pub fn new(
1947        base: Ref<NamedTypeReference>,
1948        base_offset: u64,
1949        member: StructureMember,
1950        member_index: usize,
1951    ) -> Self {
1952        Self {
1953            base,
1954            base_offset,
1955            member,
1956            member_index,
1957        }
1958    }
1959}
1960
1961#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1962pub struct BaseStructure {
1963    pub ty: Ref<NamedTypeReference>,
1964    pub offset: u64,
1965    pub width: u64,
1966}
1967
1968impl BaseStructure {
1969    pub(crate) fn from_raw(value: &BNBaseStructure) -> Self {
1970        Self {
1971            ty: unsafe { NamedTypeReference::from_raw(value.type_) }.to_owned(),
1972            offset: value.offset,
1973            width: value.width,
1974        }
1975    }
1976
1977    pub(crate) fn from_owned_raw(value: BNBaseStructure) -> Self {
1978        let owned = Self::from_raw(&value);
1979        Self::free_raw(value);
1980        owned
1981    }
1982
1983    pub(crate) fn into_raw(value: Self) -> BNBaseStructure {
1984        BNBaseStructure {
1985            type_: unsafe { Ref::into_raw(value.ty) }.handle,
1986            offset: value.offset,
1987            width: value.width,
1988        }
1989    }
1990
1991    pub(crate) fn into_owned_raw(value: &Self) -> BNBaseStructure {
1992        BNBaseStructure {
1993            type_: value.ty.handle,
1994            offset: value.offset,
1995            width: value.width,
1996        }
1997    }
1998
1999    pub(crate) fn free_raw(value: BNBaseStructure) {
2000        let _ = unsafe { NamedTypeReference::ref_from_raw(value.type_) };
2001    }
2002
2003    pub fn new(ty: Ref<NamedTypeReference>, offset: u64, width: u64) -> Self {
2004        Self { ty, offset, width }
2005    }
2006}
2007
2008#[derive(PartialEq, Eq, Hash)]
2009pub struct NamedTypeReference {
2010    pub(crate) handle: *mut BNNamedTypeReference,
2011}
2012
2013impl NamedTypeReference {
2014    pub(crate) unsafe fn from_raw(handle: *mut BNNamedTypeReference) -> Self {
2015        debug_assert!(!handle.is_null());
2016        Self { handle }
2017    }
2018
2019    pub(crate) unsafe fn ref_from_raw(handle: *mut BNNamedTypeReference) -> Ref<Self> {
2020        debug_assert!(!handle.is_null());
2021        Ref::new(Self { handle })
2022    }
2023
2024    /// Create an NTR to a type that did not come directly from a BinaryView's types list.
2025    /// That is to say, if you're referencing a new type you're GOING to add, use this.
2026    /// You should not assign type ids yourself, that is the responsibility of the BinaryView
2027    /// implementation after your types have been added. Just make sure the names match up and
2028    /// the core will do the id stuff for you.
2029    pub fn new<T: Into<QualifiedName>>(type_class: NamedTypeReferenceClass, name: T) -> Ref<Self> {
2030        let mut raw_name = QualifiedName::into_raw(name.into());
2031        let result = unsafe {
2032            Self::ref_from_raw(BNCreateNamedType(
2033                type_class,
2034                std::ptr::null(),
2035                &mut raw_name,
2036            ))
2037        };
2038        QualifiedName::free_raw(raw_name);
2039        result
2040    }
2041
2042    /// Create an NTR to a type with an existing type id, which generally means it came directly
2043    /// from a BinaryView's types list and its id was looked up using `BinaryView::get_type_id`.
2044    /// You should not assign type ids yourself: if you use this to reference a type you are going
2045    /// to create but have not yet created, you may run into problems when giving your types to
2046    /// a BinaryView.
2047    pub fn new_with_id<T: Into<QualifiedName>>(
2048        type_class: NamedTypeReferenceClass,
2049        type_id: &str,
2050        name: T,
2051    ) -> Ref<Self> {
2052        let type_id = type_id.to_cstr();
2053        let mut raw_name = QualifiedName::into_raw(name.into());
2054        let result = unsafe {
2055            Self::ref_from_raw(BNCreateNamedType(
2056                type_class,
2057                type_id.as_ref().as_ptr() as _,
2058                &mut raw_name,
2059            ))
2060        };
2061        QualifiedName::free_raw(raw_name);
2062        result
2063    }
2064
2065    pub fn name(&self) -> QualifiedName {
2066        let raw_name = unsafe { BNGetTypeReferenceName(self.handle) };
2067        QualifiedName::from_owned_raw(raw_name)
2068    }
2069
2070    pub fn id(&self) -> String {
2071        unsafe { BnString::into_string(BNGetTypeReferenceId(self.handle)) }
2072    }
2073
2074    pub fn class(&self) -> NamedTypeReferenceClass {
2075        unsafe { BNGetTypeReferenceClass(self.handle) }
2076    }
2077
2078    fn target_helper(&self, bv: &BinaryView, visited: &mut HashSet<String>) -> Option<Ref<Type>> {
2079        let ty = bv.type_by_id(&self.id())?;
2080        match ty.type_class() {
2081            TypeClass::NamedTypeReferenceClass => {
2082                // Recurse into the NTR type until we get the target type.
2083                let ntr = ty
2084                    .get_named_type_reference()
2085                    .expect("NTR type class should always have a valid NTR");
2086                match visited.insert(ntr.id()) {
2087                    true => ntr.target_helper(bv, visited),
2088                    // Cyclic reference, return None.
2089                    false => None,
2090                }
2091            }
2092            // Found target type
2093            _ => Some(ty),
2094        }
2095    }
2096
2097    /// Type referenced by this [`NamedTypeReference`].
2098    ///
2099    /// Will return `None` if the reference is cyclic, or the target type does not exist.
2100    pub fn target(&self, bv: &BinaryView) -> Option<Ref<Type>> {
2101        self.target_helper(bv, &mut HashSet::new())
2102    }
2103}
2104
2105impl ToOwned for NamedTypeReference {
2106    type Owned = Ref<Self>;
2107
2108    fn to_owned(&self) -> Self::Owned {
2109        unsafe { RefCountable::inc_ref(self) }
2110    }
2111}
2112
2113unsafe impl RefCountable for NamedTypeReference {
2114    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
2115        Self::ref_from_raw(BNNewNamedTypeReference(handle.handle))
2116    }
2117
2118    unsafe fn dec_ref(handle: &Self) {
2119        BNFreeNamedTypeReference(handle.handle)
2120    }
2121}
2122
2123impl Debug for NamedTypeReference {
2124    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2125        write!(f, "{} (id: {})", self.name(), self.id())
2126    }
2127}
2128
2129// TODO: Document usage, specifically how to make a qualified name and why it exists.
2130#[derive(Default, Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
2131pub struct QualifiedName {
2132    // TODO: Make this Option<String> where default is "::".
2133    pub separator: String,
2134    pub items: Vec<String>,
2135}
2136
2137impl QualifiedName {
2138    pub(crate) fn from_raw(value: &BNQualifiedName) -> Self {
2139        // TODO: This could be improved...
2140        let raw_names = unsafe { std::slice::from_raw_parts(value.name, value.nameCount) };
2141        let items = raw_names
2142            .iter()
2143            .filter_map(|&raw_name| raw_to_string(raw_name as *const _))
2144            .collect();
2145        let separator = raw_to_string(value.join).unwrap();
2146        Self { items, separator }
2147    }
2148
2149    pub(crate) fn from_owned_raw(value: BNQualifiedName) -> Self {
2150        let result = Self::from_raw(&value);
2151        Self::free_raw(value);
2152        result
2153    }
2154
2155    pub fn into_raw(value: Self) -> BNQualifiedName {
2156        let bn_join = BnString::new(&value.separator);
2157        BNQualifiedName {
2158            // NOTE: Leaking string list must be freed by core or us!
2159            name: strings_to_string_list(&value.items),
2160            // NOTE: Leaking string must be freed by core or us!
2161            join: BnString::into_raw(bn_join),
2162            nameCount: value.items.len(),
2163        }
2164    }
2165
2166    pub(crate) fn free_raw(value: BNQualifiedName) {
2167        unsafe { BnString::free_raw(value.join) };
2168        unsafe { BNFreeStringList(value.name, value.nameCount) };
2169    }
2170
2171    pub fn new(items: Vec<String>) -> Self {
2172        Self::new_with_separator(items, "::".to_string())
2173    }
2174
2175    pub fn new_with_separator(items: Vec<String>, separator: String) -> Self {
2176        Self { items, separator }
2177    }
2178
2179    pub fn with_item(&self, item: impl Into<String>) -> Self {
2180        let mut items = self.items.clone();
2181        items.push(item.into());
2182        Self::new_with_separator(items, self.separator.clone())
2183    }
2184
2185    pub fn push(&mut self, item: String) {
2186        self.items.push(item);
2187    }
2188
2189    pub fn pop(&mut self) -> Option<String> {
2190        self.items.pop()
2191    }
2192
2193    pub fn insert(&mut self, index: usize, item: String) {
2194        if index <= self.items.len() {
2195            self.items.insert(index, item);
2196        }
2197    }
2198
2199    pub fn split_last(&self) -> Option<(String, QualifiedName)> {
2200        self.items.split_last().map(|(a, b)| {
2201            (
2202                a.to_owned(),
2203                QualifiedName::new_with_separator(b.to_vec(), self.separator.clone()),
2204            )
2205        })
2206    }
2207
2208    /// Replaces all occurrences of a substring with another string in all items of the `QualifiedName`
2209    /// and returns an owned version of the modified `QualifiedName`.
2210    ///
2211    /// # Example
2212    ///
2213    /// ```
2214    /// use binaryninja::types::QualifiedName;
2215    ///
2216    /// let qualified_name =
2217    ///     QualifiedName::new(vec!["my::namespace".to_string(), "mytype".to_string()]);
2218    /// let replaced = qualified_name.replace("my", "your");
2219    /// assert_eq!(
2220    ///     replaced.items,
2221    ///     vec!["your::namespace".to_string(), "yourtype".to_string()]
2222    /// );
2223    /// ```
2224    pub fn replace(&self, from: &str, to: &str) -> Self {
2225        Self {
2226            items: self
2227                .items
2228                .iter()
2229                .map(|item| item.replace(from, to))
2230                .collect(),
2231            separator: self.separator.clone(),
2232        }
2233    }
2234
2235    /// Returns the last item, or `None` if it is empty.
2236    pub fn last(&self) -> Option<&String> {
2237        self.items.last()
2238    }
2239
2240    /// Returns a mutable reference to the last item, or `None` if it is empty.
2241    pub fn last_mut(&mut self) -> Option<&mut String> {
2242        self.items.last_mut()
2243    }
2244
2245    pub fn len(&self) -> usize {
2246        self.items.len()
2247    }
2248
2249    /// A [`QualifiedName`] is empty if it has no items.
2250    ///
2251    /// If you want to know if the unqualified name is empty (i.e. no characters)
2252    /// you must first convert the qualified name to unqualified via the `to_string` method.
2253    pub fn is_empty(&self) -> bool {
2254        self.items.is_empty()
2255    }
2256}
2257
2258impl From<String> for QualifiedName {
2259    fn from(value: String) -> Self {
2260        Self {
2261            items: vec![value],
2262            // TODO: See comment in struct def.
2263            separator: String::from("::"),
2264        }
2265    }
2266}
2267
2268impl From<&str> for QualifiedName {
2269    fn from(value: &str) -> Self {
2270        Self::from(value.to_string())
2271    }
2272}
2273
2274impl From<&String> for QualifiedName {
2275    fn from(value: &String) -> Self {
2276        Self::from(value.to_owned())
2277    }
2278}
2279
2280impl From<Cow<'_, str>> for QualifiedName {
2281    fn from(value: Cow<'_, str>) -> Self {
2282        Self::from(value.to_string())
2283    }
2284}
2285
2286impl From<Vec<String>> for QualifiedName {
2287    fn from(value: Vec<String>) -> Self {
2288        Self::new(value)
2289    }
2290}
2291
2292impl From<Vec<&str>> for QualifiedName {
2293    fn from(value: Vec<&str>) -> Self {
2294        value
2295            .iter()
2296            .map(ToString::to_string)
2297            .collect::<Vec<_>>()
2298            .into()
2299    }
2300}
2301
2302impl From<QualifiedName> for String {
2303    fn from(value: QualifiedName) -> Self {
2304        value.to_string()
2305    }
2306}
2307
2308impl Index<usize> for QualifiedName {
2309    type Output = String;
2310
2311    fn index(&self, index: usize) -> &Self::Output {
2312        &self.items[index]
2313    }
2314}
2315
2316impl IndexMut<usize> for QualifiedName {
2317    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
2318        &mut self.items[index]
2319    }
2320}
2321
2322impl Display for QualifiedName {
2323    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2324        write!(f, "{}", self.items.join(&self.separator))
2325    }
2326}
2327
2328impl CoreArrayProvider for QualifiedName {
2329    type Raw = BNQualifiedName;
2330    type Context = ();
2331    type Wrapped<'a> = Self;
2332}
2333
2334unsafe impl CoreArrayProviderInner for QualifiedName {
2335    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
2336        BNFreeTypeNameList(raw, count);
2337    }
2338
2339    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
2340        QualifiedName::from_raw(raw)
2341    }
2342}
2343
2344#[derive(Debug, Clone, Hash, PartialEq, Eq)]
2345pub struct QualifiedNameAndType {
2346    pub name: QualifiedName,
2347    pub ty: Ref<Type>,
2348}
2349
2350impl QualifiedNameAndType {
2351    pub(crate) fn from_raw(value: &BNQualifiedNameAndType) -> Self {
2352        Self {
2353            name: QualifiedName::from_raw(&value.name),
2354            ty: unsafe { Type::from_raw(value.type_).to_owned() },
2355        }
2356    }
2357
2358    pub(crate) fn from_owned_raw(value: BNQualifiedNameAndType) -> Self {
2359        let owned = Self::from_raw(&value);
2360        Self::free_raw(value);
2361        owned
2362    }
2363
2364    pub(crate) fn into_raw(value: Self) -> BNQualifiedNameAndType {
2365        BNQualifiedNameAndType {
2366            name: QualifiedName::into_raw(value.name),
2367            type_: unsafe { Ref::into_raw(value.ty).handle },
2368        }
2369    }
2370
2371    pub(crate) fn free_raw(value: BNQualifiedNameAndType) {
2372        QualifiedName::free_raw(value.name);
2373        let _ = unsafe { Type::ref_from_raw(value.type_) };
2374    }
2375
2376    pub fn new(name: QualifiedName, ty: Ref<Type>) -> Self {
2377        Self { name, ty }
2378    }
2379}
2380
2381impl<T> From<(T, Ref<Type>)> for QualifiedNameAndType
2382where
2383    T: Into<QualifiedName>,
2384{
2385    fn from(value: (T, Ref<Type>)) -> Self {
2386        Self {
2387            name: value.0.into(),
2388            ty: value.1,
2389        }
2390    }
2391}
2392
2393impl<T> From<(T, &Type)> for QualifiedNameAndType
2394where
2395    T: Into<QualifiedName>,
2396{
2397    fn from(value: (T, &Type)) -> Self {
2398        let ty = value.1.to_owned();
2399        Self {
2400            name: value.0.into(),
2401            ty,
2402        }
2403    }
2404}
2405
2406impl CoreArrayProvider for QualifiedNameAndType {
2407    type Raw = BNQualifiedNameAndType;
2408    type Context = ();
2409    type Wrapped<'a> = Self;
2410}
2411
2412unsafe impl CoreArrayProviderInner for QualifiedNameAndType {
2413    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
2414        BNFreeTypeAndNameList(raw, count);
2415    }
2416
2417    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
2418        QualifiedNameAndType::from_raw(raw)
2419    }
2420}
2421
2422#[derive(Debug, Clone, Hash, PartialEq, Eq)]
2423pub struct QualifiedNameTypeAndId {
2424    pub name: QualifiedName,
2425    pub ty: Ref<Type>,
2426    pub id: String,
2427}
2428
2429impl QualifiedNameTypeAndId {
2430    pub(crate) fn from_raw(value: &BNQualifiedNameTypeAndId) -> Self {
2431        Self {
2432            name: QualifiedName::from_raw(&value.name),
2433            ty: unsafe { Type::from_raw(value.type_) }.to_owned(),
2434            id: raw_to_string(value.id).unwrap(),
2435        }
2436    }
2437
2438    pub(crate) fn from_owned_raw(value: BNQualifiedNameTypeAndId) -> Self {
2439        let owned = Self::from_raw(&value);
2440        Self::free_raw(value);
2441        owned
2442    }
2443
2444    pub(crate) fn into_raw(value: Self) -> BNQualifiedNameTypeAndId {
2445        let bn_id = BnString::new(value.id);
2446        BNQualifiedNameTypeAndId {
2447            name: QualifiedName::into_raw(value.name),
2448            id: BnString::into_raw(bn_id),
2449            type_: unsafe { Ref::into_raw(value.ty) }.handle,
2450        }
2451    }
2452
2453    pub(crate) fn free_raw(value: BNQualifiedNameTypeAndId) {
2454        QualifiedName::free_raw(value.name);
2455        let _ = unsafe { Type::ref_from_raw(value.type_) };
2456        let _ = unsafe { BnString::from_raw(value.id) };
2457    }
2458}
2459
2460impl CoreArrayProvider for QualifiedNameTypeAndId {
2461    type Raw = BNQualifiedNameTypeAndId;
2462    type Context = ();
2463    type Wrapped<'a> = QualifiedNameTypeAndId;
2464}
2465
2466unsafe impl CoreArrayProviderInner for QualifiedNameTypeAndId {
2467    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
2468        BNFreeTypeIdList(raw, count);
2469    }
2470
2471    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
2472        QualifiedNameTypeAndId::from_raw(raw)
2473    }
2474}
2475
2476// TODO: Document how this type is used for many different purposes. (this is literally (string, type))
2477// TODO: Ex. the name might be the parser it came from
2478// TODO: Ex. the name might be the param name for an intrinsic input
2479// TODO: Should we make new types for each varying use case?
2480#[derive(Debug, Clone, Eq, PartialEq, Hash)]
2481pub struct NameAndType {
2482    pub name: String,
2483    pub ty: Conf<Ref<Type>>,
2484}
2485
2486impl NameAndType {
2487    pub(crate) fn from_raw(value: &BNNameAndType) -> Self {
2488        Self {
2489            // TODO: I dislike using this function here.
2490            name: raw_to_string(value.name as *mut _).unwrap(),
2491            ty: Conf::new(
2492                unsafe { Type::from_raw(value.type_).to_owned() },
2493                value.typeConfidence,
2494            ),
2495        }
2496    }
2497
2498    pub(crate) fn from_owned_raw(value: BNNameAndType) -> Self {
2499        let owned = Self::from_raw(&value);
2500        Self::free_raw(value);
2501        owned
2502    }
2503
2504    pub(crate) fn into_raw(value: Self) -> BNNameAndType {
2505        let bn_name = BnString::new(value.name);
2506        BNNameAndType {
2507            name: BnString::into_raw(bn_name),
2508            type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
2509            typeConfidence: value.ty.confidence,
2510        }
2511    }
2512
2513    pub(crate) fn free_raw(value: BNNameAndType) {
2514        unsafe { BnString::free_raw(value.name) };
2515        let _ = unsafe { Type::ref_from_raw(value.type_) };
2516    }
2517
2518    pub fn new(name: impl Into<String>, ty: Conf<Ref<Type>>) -> Self {
2519        Self {
2520            name: name.into(),
2521            ty,
2522        }
2523    }
2524}
2525
2526impl CoreArrayProvider for NameAndType {
2527    type Raw = BNNameAndType;
2528    type Context = ();
2529    type Wrapped<'a> = Self;
2530}
2531
2532unsafe impl CoreArrayProviderInner for NameAndType {
2533    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
2534        BNFreeNameAndTypeList(raw, count);
2535    }
2536
2537    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
2538        NameAndType::from_raw(raw)
2539    }
2540}