binaryninja/
types.rs

1// Copyright 2021-2026 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//! The model for representing types in Binary Ninja.
15//!
16//! [`Type`]'s are fundamental to analysis. With types, you can influence how decompilation resolves accesses,
17//! renders data, and tell the analysis of properties such as volatility and constness.
18//!
19//! Types are typically stored within a [`BinaryView`], [`TypeArchive`] or a [`TypeLibrary`].
20//!
21//! Types can be created using the [`TypeBuilder`] or one of the convenience functions. Another way
22//! to create a type is with a [`TypeParser`] if you have C type definitions.
23//!
24//! Some interfaces may expect to be passed a [`TypeContainer`] which itself does not store any type
25//! information, rather a generic interface to query for types by name or by id.
26
27pub mod archive;
28pub mod container;
29pub mod enumeration;
30pub mod library;
31pub mod parser;
32pub mod printer;
33pub mod structure;
34
35use binaryninjacore_sys::*;
36
37use crate::{
38    architecture::Architecture,
39    binary_view::BinaryView,
40    calling_convention::CoreCallingConvention,
41    rc::*,
42    string::{BnString, IntoCStr},
43};
44
45use crate::confidence::{Conf, MAX_CONFIDENCE, MIN_CONFIDENCE};
46use crate::string::raw_to_string;
47use crate::variable::{Variable, VariableSourceType};
48use std::num::NonZeroUsize;
49use std::{
50    collections::HashSet,
51    fmt::{Debug, Display, Formatter},
52    hash::{Hash, Hasher},
53    iter::IntoIterator,
54};
55
56pub use archive::{TypeArchive, TypeArchiveId, TypeArchiveSnapshotId};
57pub use container::TypeContainer;
58pub use enumeration::{Enumeration, EnumerationBuilder, EnumerationMember};
59pub use library::TypeLibrary;
60pub use parser::{
61    CoreTypeParser, ParsedType, TypeParser, TypeParserError, TypeParserErrorSeverity,
62    TypeParserResult,
63};
64pub use printer::{CoreTypePrinter, TypePrinter};
65pub use structure::{
66    BaseStructure, InheritedStructureMember, Structure, StructureBuilder, StructureMember,
67};
68
69#[deprecated(note = "Use crate::qualified_name::QualifiedName instead")]
70// Re-export QualifiedName so that we do not break public consumers.
71pub use crate::qualified_name::QualifiedName;
72
73pub type StructureType = BNStructureVariant;
74pub type ReferenceType = BNReferenceType;
75pub type TypeClass = BNTypeClass;
76pub type NamedTypeReferenceClass = BNNamedTypeReferenceClass;
77pub type MemberAccess = BNMemberAccess;
78pub type MemberScope = BNMemberScope;
79pub type IntegerDisplayType = BNIntegerDisplayType;
80pub type PointerBaseType = BNPointerBaseType;
81
82#[derive(PartialEq, Eq, Hash)]
83pub struct TypeBuilder {
84    pub(crate) handle: *mut BNTypeBuilder,
85}
86
87impl TypeBuilder {
88    pub fn new(t: &Type) -> Self {
89        unsafe { Self::from_raw(BNCreateTypeBuilderFromType(t.handle)) }
90    }
91
92    pub(crate) unsafe fn from_raw(handle: *mut BNTypeBuilder) -> Self {
93        debug_assert!(!handle.is_null());
94        Self { handle }
95    }
96
97    /// Turn the [`TypeBuilder`] into a [`Type`].
98    pub fn finalize(&self) -> Ref<Type> {
99        unsafe { Type::ref_from_raw(BNFinalizeTypeBuilder(self.handle)) }
100    }
101
102    pub fn set_can_return<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
103        let mut bool_with_confidence = value.into().into();
104        unsafe { BNSetFunctionTypeBuilderCanReturn(self.handle, &mut bool_with_confidence) };
105        self
106    }
107
108    pub fn set_pure<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
109        let mut bool_with_confidence = value.into().into();
110        unsafe { BNSetTypeBuilderPure(self.handle, &mut bool_with_confidence) };
111        self
112    }
113
114    pub fn set_const<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
115        let mut bool_with_confidence = value.into().into();
116        unsafe { BNTypeBuilderSetConst(self.handle, &mut bool_with_confidence) };
117        self
118    }
119
120    pub fn set_volatile<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
121        let mut bool_with_confidence = value.into().into();
122        unsafe { BNTypeBuilderSetVolatile(self.handle, &mut bool_with_confidence) };
123        self
124    }
125
126    /// Set the width of the type.
127    ///
128    /// Typically only done for named type references, which will not have their width set otherwise.
129    pub fn set_width(&self, width: usize) -> &Self {
130        unsafe { BNTypeBuilderSetWidth(self.handle, width) }
131        self
132    }
133
134    /// Set the alignment of the type.
135    ///
136    /// Typically only done for named type references, which will not have their alignment set otherwise.
137    pub fn set_alignment(&self, alignment: usize) -> &Self {
138        unsafe { BNTypeBuilderSetAlignment(self.handle, alignment) }
139        self
140    }
141
142    pub fn set_pointer_base(&self, base_type: PointerBaseType, base_offset: i64) -> &Self {
143        unsafe { BNSetTypeBuilderPointerBase(self.handle, base_type, base_offset) }
144        self
145    }
146
147    pub fn set_child_type<'a, T: Into<Conf<&'a Type>>>(&self, ty: T) -> &Self {
148        let mut type_with_confidence = Conf::<&Type>::into_raw(ty.into());
149        unsafe { BNTypeBuilderSetChildType(self.handle, &mut type_with_confidence) };
150        self
151    }
152
153    /// This is an alias for [`Self::set_child_type`].
154    pub fn set_target<'a, T: Into<Conf<&'a Type>>>(&self, ty: T) -> &Self {
155        self.set_child_type(ty)
156    }
157
158    /// This is an alias for [`Self::set_child_type`].
159    pub fn set_element_type<'a, T: Into<Conf<&'a Type>>>(&self, ty: T) -> &Self {
160        self.set_child_type(ty)
161    }
162
163    /// This is an alias for [`Self::set_child_type`].
164    pub fn set_return_value<'a, T: Into<Conf<&'a Type>>>(&self, ty: T) -> &Self {
165        self.set_child_type(ty)
166    }
167
168    pub fn set_signed<T: Into<Conf<bool>>>(&self, value: T) -> &Self {
169        let mut bool_with_confidence = value.into().into();
170        unsafe { BNTypeBuilderSetSigned(self.handle, &mut bool_with_confidence) };
171        self
172    }
173
174    pub fn set_integer_display_type(&self, display_type: IntegerDisplayType) -> &Self {
175        unsafe { BNSetIntegerTypeDisplayType(self.handle, display_type) };
176        self
177    }
178
179    // Readable properties
180
181    pub fn type_class(&self) -> TypeClass {
182        unsafe { BNGetTypeBuilderClass(self.handle) }
183    }
184
185    pub fn width(&self) -> u64 {
186        unsafe { BNGetTypeBuilderWidth(self.handle) }
187    }
188
189    pub fn alignment(&self) -> usize {
190        unsafe { BNGetTypeBuilderAlignment(self.handle) }
191    }
192
193    pub fn is_signed(&self) -> Conf<bool> {
194        unsafe { BNIsTypeBuilderSigned(self.handle).into() }
195    }
196
197    pub fn integer_display_type(&self) -> IntegerDisplayType {
198        self.finalize().integer_display_type()
199    }
200
201    pub fn is_const(&self) -> Conf<bool> {
202        unsafe { BNIsTypeBuilderConst(self.handle).into() }
203    }
204
205    pub fn is_volatile(&self) -> Conf<bool> {
206        unsafe { BNIsTypeBuilderVolatile(self.handle).into() }
207    }
208
209    pub fn is_floating_point(&self) -> bool {
210        unsafe { BNIsTypeBuilderFloatingPoint(self.handle) }
211    }
212
213    pub fn child_type(&self) -> Option<Conf<Ref<Type>>> {
214        let raw_target = unsafe { BNGetTypeBuilderChildType(self.handle) };
215        match raw_target.type_.is_null() {
216            false => Some(Conf::<Ref<Type>>::from_owned_raw(raw_target)),
217            true => None,
218        }
219    }
220
221    /// This is an alias for [`Self::child_type`].
222    pub fn target(&self) -> Option<Conf<Ref<Type>>> {
223        self.child_type()
224    }
225
226    /// This is an alias for [`Self::child_type`].
227    pub fn element_type(&self) -> Option<Conf<Ref<Type>>> {
228        self.child_type()
229    }
230
231    /// This is an alias for [`Self::child_type`].
232    pub fn return_value(&self) -> Option<Conf<Ref<Type>>> {
233        self.child_type()
234    }
235
236    pub fn calling_convention(&self) -> Option<Conf<Ref<CoreCallingConvention>>> {
237        let raw_convention_confidence = unsafe { BNGetTypeBuilderCallingConvention(self.handle) };
238        match raw_convention_confidence.convention.is_null() {
239            false => Some(Conf::<Ref<CoreCallingConvention>>::from_owned_raw(
240                raw_convention_confidence,
241            )),
242            true => None,
243        }
244    }
245
246    pub fn parameters(&self) -> Option<Vec<FunctionParameter>> {
247        unsafe {
248            let mut count = 0;
249            let raw_parameters_ptr = BNGetTypeBuilderParameters(self.handle, &mut count);
250            match raw_parameters_ptr.is_null() {
251                false => {
252                    let raw_parameters = std::slice::from_raw_parts(raw_parameters_ptr, count);
253                    let parameters = raw_parameters
254                        .iter()
255                        .map(FunctionParameter::from_raw)
256                        .collect();
257                    BNFreeTypeParameterList(raw_parameters_ptr, count);
258                    Some(parameters)
259                }
260                true => None,
261            }
262        }
263    }
264
265    pub fn has_variable_arguments(&self) -> Conf<bool> {
266        unsafe { BNTypeBuilderHasVariableArguments(self.handle).into() }
267    }
268
269    pub fn can_return(&self) -> Conf<bool> {
270        unsafe { BNFunctionTypeBuilderCanReturn(self.handle).into() }
271    }
272
273    pub fn pure(&self) -> Conf<bool> {
274        unsafe { BNIsTypeBuilderPure(self.handle).into() }
275    }
276
277    // TODO: This naming is problematic... rename to `as_structure`?
278    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
279    pub fn get_structure(&self) -> Option<Ref<Structure>> {
280        let raw_struct_ptr = unsafe { BNGetTypeBuilderStructure(self.handle) };
281        match raw_struct_ptr.is_null() {
282            false => Some(unsafe { Structure::ref_from_raw(raw_struct_ptr) }),
283            true => None,
284        }
285    }
286
287    // TODO: This naming is problematic... rename to `as_enumeration`?
288    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
289    pub fn get_enumeration(&self) -> Option<Ref<Enumeration>> {
290        let raw_enum_ptr = unsafe { BNGetTypeBuilderEnumeration(self.handle) };
291        match raw_enum_ptr.is_null() {
292            false => Some(unsafe { Enumeration::ref_from_raw(raw_enum_ptr) }),
293            true => None,
294        }
295    }
296
297    // TODO: This naming is problematic... rename to `as_named_type_reference`?
298    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
299    pub fn get_named_type_reference(&self) -> Option<Ref<NamedTypeReference>> {
300        let raw_type_ref_ptr = unsafe { BNGetTypeBuilderNamedTypeReference(self.handle) };
301        match raw_type_ref_ptr.is_null() {
302            false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
303            true => None,
304        }
305    }
306
307    pub fn count(&self) -> u64 {
308        unsafe { BNGetTypeBuilderElementCount(self.handle) }
309    }
310
311    pub fn offset(&self) -> u64 {
312        unsafe { BNGetTypeBuilderOffset(self.handle) }
313    }
314
315    pub fn stack_adjustment(&self) -> Conf<i64> {
316        unsafe { BNGetTypeBuilderStackAdjustment(self.handle).into() }
317    }
318
319    pub fn pointer_base_type(&self) -> PointerBaseType {
320        unsafe { BNTypeBuilderGetPointerBaseType(self.handle) }
321    }
322
323    pub fn pointer_base_offset(&self) -> i64 {
324        unsafe { BNTypeBuilderGetPointerBaseOffset(self.handle) }
325    }
326
327    // TODO : This and properties
328    // pub fn tokens(&self) -> ? {}
329
330    /// Create a void [`TypeBuilder`]. Analogous to [`Type::void`].
331    pub fn void() -> Self {
332        unsafe { Self::from_raw(BNCreateVoidTypeBuilder()) }
333    }
334
335    /// Create a bool [`TypeBuilder`]. Analogous to [`Type::bool`].
336    pub fn bool() -> Self {
337        unsafe { Self::from_raw(BNCreateBoolTypeBuilder()) }
338    }
339
340    /// Create a signed one byte integer [`TypeBuilder`]. Analogous to [`Type::char`].
341    pub fn char() -> Self {
342        Self::int(1, true)
343    }
344
345    /// Create an integer [`TypeBuilder`] with the given width and signedness. Analogous to [`Type::int`].
346    pub fn int(width: usize, is_signed: bool) -> Self {
347        let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
348
349        unsafe {
350            Self::from_raw(BNCreateIntegerTypeBuilder(
351                width,
352                &mut is_signed,
353                c"".as_ptr() as _,
354            ))
355        }
356    }
357
358    /// Create an integer [`TypeBuilder`] with the given width and signedness and an alternative name.
359    /// Analogous to [`Type::named_int`].
360    pub fn named_int(width: usize, is_signed: bool, alt_name: &str) -> Self {
361        let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
362        let alt_name = alt_name.to_cstr();
363
364        unsafe {
365            Self::from_raw(BNCreateIntegerTypeBuilder(
366                width,
367                &mut is_signed,
368                alt_name.as_ref().as_ptr() as _,
369            ))
370        }
371    }
372
373    /// Create a float [`TypeBuilder`] with the given width. Analogous to [`Type::float`].
374    pub fn float(width: usize) -> Self {
375        unsafe { Self::from_raw(BNCreateFloatTypeBuilder(width, c"".as_ptr())) }
376    }
377
378    /// Create a float [`TypeBuilder`] with the given width and alternative name. Analogous to [`Type::named_float`].
379    pub fn named_float(width: usize, alt_name: &str) -> Self {
380        let alt_name = alt_name.to_cstr();
381        unsafe { Self::from_raw(BNCreateFloatTypeBuilder(width, alt_name.as_ptr())) }
382    }
383
384    /// Create an array [`TypeBuilder`] with the given element type and count. Analogous to [`Type::array`].
385    pub fn array<'a, T: Into<Conf<&'a Type>>>(ty: T, count: u64) -> Self {
386        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
387        unsafe { Self::from_raw(BNCreateArrayTypeBuilder(&owned_raw_ty, count)) }
388    }
389
390    /// Create an enumeration [`TypeBuilder`] with the given width and signedness. Analogous to [`Type::enumeration`].
391    ///
392    /// ## NOTE
393    ///
394    /// 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.
395    ///
396    /// For simplicity's sake, that convention isn't followed, and you can query [`Architecture::default_integer_size`] if you need to.
397    pub fn enumeration<T: Into<Conf<bool>>>(
398        enumeration: &Enumeration,
399        width: NonZeroUsize,
400        is_signed: T,
401    ) -> Self {
402        unsafe {
403            Self::from_raw(BNCreateEnumerationTypeBuilder(
404                // TODO: We pass nullptr arch, really we should not even be passing arch.
405                std::ptr::null_mut(),
406                enumeration.handle,
407                width.get(),
408                &mut is_signed.into().into(),
409            ))
410        }
411    }
412
413    /// Create a structure [`TypeBuilder`]. Analogous to [`Type::structure`].
414    pub fn structure(structure_type: &Structure) -> Self {
415        unsafe { Self::from_raw(BNCreateStructureTypeBuilder(structure_type.handle)) }
416    }
417
418    /// Create a named type reference [`TypeBuilder`]. Analogous to [`Type::named_type`].
419    pub fn named_type(type_reference: &NamedTypeReference) -> Self {
420        let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
421        let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
422        unsafe {
423            Self::from_raw(BNCreateNamedTypeReferenceBuilder(
424                type_reference.handle,
425                0,
426                1,
427                &mut is_const,
428                &mut is_volatile,
429            ))
430        }
431    }
432
433    /// Create a named type reference [`TypeBuilder`] from a type and name. Analogous to [`Type::named_type_from_type`].
434    pub fn named_type_from_type<T: Into<QualifiedName>>(name: T, t: &Type) -> Self {
435        let mut raw_name = QualifiedName::into_raw(name.into());
436        let id = c"";
437
438        let result = unsafe {
439            Self::from_raw(BNCreateNamedTypeReferenceBuilderFromTypeAndId(
440                id.as_ptr() as *mut _,
441                &mut raw_name,
442                t.handle,
443            ))
444        };
445        QualifiedName::free_raw(raw_name);
446        result
447    }
448
449    // TODO: Deprecate this for a FunctionBuilder (along with the Type variant?)
450    /// NOTE: This is likely to be deprecated and removed in favor of a function type builder, please
451    /// use [`Type::function`] where possible.
452    pub fn function<'a, T: Into<Conf<&'a Type>>>(
453        return_type: T,
454        parameters: Vec<FunctionParameter>,
455        variable_arguments: bool,
456    ) -> Self {
457        let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
458        let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
459        let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
460        let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
461
462        let mut raw_calling_convention: BNCallingConventionWithConfidence =
463            BNCallingConventionWithConfidence {
464                convention: std::ptr::null_mut(),
465                confidence: MIN_CONFIDENCE,
466            };
467
468        let mut stack_adjust = Conf::new(0, MIN_CONFIDENCE).into();
469        let mut raw_parameters = parameters
470            .into_iter()
471            .map(FunctionParameter::into_raw)
472            .collect::<Vec<_>>();
473        let reg_stack_adjust_regs = std::ptr::null_mut();
474        let reg_stack_adjust_values = std::ptr::null_mut();
475
476        let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
477            regs: std::ptr::null_mut(),
478            count: 0,
479            confidence: 0,
480        };
481
482        let result = unsafe {
483            Self::from_raw(BNCreateFunctionTypeBuilder(
484                &mut owned_raw_return_type,
485                &mut raw_calling_convention,
486                raw_parameters.as_mut_ptr(),
487                raw_parameters.len(),
488                &mut variable_arguments,
489                &mut can_return,
490                &mut stack_adjust,
491                reg_stack_adjust_regs,
492                reg_stack_adjust_values,
493                0,
494                &mut return_regs,
495                BNNameType::NoNameType,
496                &mut pure,
497            ))
498        };
499
500        for raw_param in raw_parameters {
501            FunctionParameter::free_raw(raw_param);
502        }
503
504        result
505    }
506
507    // TODO: Deprecate this for a FunctionBuilder (along with the Type variant?)
508    /// NOTE: This is likely to be deprecated and removed in favor of a function type builder, please
509    /// use [`Type::function_with_opts`] where possible.
510    pub fn function_with_opts<
511        'a,
512        T: Into<Conf<&'a Type>>,
513        C: Into<Conf<Ref<CoreCallingConvention>>>,
514    >(
515        return_type: T,
516        parameters: &[FunctionParameter],
517        variable_arguments: bool,
518        calling_convention: C,
519        stack_adjust: Conf<i64>,
520    ) -> Self {
521        let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
522        let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
523        let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
524        let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
525
526        let mut owned_raw_calling_convention =
527            Conf::<Ref<CoreCallingConvention>>::into_owned_raw(&calling_convention.into());
528
529        let mut stack_adjust = stack_adjust.into();
530        let mut raw_parameters = parameters
531            .iter()
532            .cloned()
533            .map(FunctionParameter::into_raw)
534            .collect::<Vec<_>>();
535
536        // TODO: Update type signature and include these (will be a breaking change)
537        let reg_stack_adjust_regs = std::ptr::null_mut();
538        let reg_stack_adjust_values = std::ptr::null_mut();
539
540        let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
541            regs: std::ptr::null_mut(),
542            count: 0,
543            confidence: 0,
544        };
545
546        let result = unsafe {
547            Self::from_raw(BNCreateFunctionTypeBuilder(
548                &mut owned_raw_return_type,
549                &mut owned_raw_calling_convention,
550                raw_parameters.as_mut_ptr(),
551                raw_parameters.len(),
552                &mut variable_arguments,
553                &mut can_return,
554                &mut stack_adjust,
555                reg_stack_adjust_regs,
556                reg_stack_adjust_values,
557                0,
558                &mut return_regs,
559                BNNameType::NoNameType,
560                &mut pure,
561            ))
562        };
563
564        for raw_param in raw_parameters {
565            FunctionParameter::free_raw(raw_param);
566        }
567
568        result
569    }
570
571    /// Create a pointer [`TypeBuilder`] with the given target type. Analogous to [`Type::pointer`].
572    pub fn pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Self {
573        Self::pointer_with_options(arch, ty, false, false, None)
574    }
575
576    /// Create a const pointer [`TypeBuilder`] with the given target type. Analogous to [`Type::const_pointer`].
577    pub fn const_pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Self {
578        Self::pointer_with_options(arch, ty, true, false, None)
579    }
580
581    pub fn pointer_with_options<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
582        arch: &A,
583        ty: T,
584        is_const: bool,
585        is_volatile: bool,
586        ref_type: Option<ReferenceType>,
587    ) -> Self {
588        let arch_ptr_size = arch.address_size();
589        Self::pointer_of_width(ty, arch_ptr_size, is_const, is_volatile, ref_type)
590    }
591
592    pub fn pointer_of_width<'a, T: Into<Conf<&'a Type>>>(
593        ty: T,
594        size: usize,
595        is_const: bool,
596        is_volatile: bool,
597        ref_type: Option<ReferenceType>,
598    ) -> Self {
599        let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
600        let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
601        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
602        unsafe {
603            Self::from_raw(BNCreatePointerTypeBuilderOfWidth(
604                size,
605                &owned_raw_ty,
606                &mut is_const,
607                &mut is_volatile,
608                ref_type.unwrap_or(ReferenceType::PointerReferenceType),
609            ))
610        }
611    }
612}
613
614impl Display for TypeBuilder {
615    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
616        write!(f, "{}", unsafe {
617            BnString::into_string(BNGetTypeBuilderString(self.handle, std::ptr::null_mut()))
618        })
619    }
620}
621
622impl Drop for TypeBuilder {
623    fn drop(&mut self) {
624        unsafe { BNFreeTypeBuilder(self.handle) };
625    }
626}
627
628/// The core model for types in Binary Ninja.
629///
630/// A [`Type`] is how we model the storage of a [`Variable`] or [`crate::variable::DataVariable`] as
631/// well as propagate information such as the constness of a variable. Types are also used to declare
632/// function signatures, such as the [`FunctionParameter`]'s and return type.
633///
634/// Types are immutable. To change a type, you must create a new one either using [`TypeBuilder`] or
635/// one of the helper functions:
636///
637/// - [`Type::void`]
638/// - [`Type::bool`]
639/// - [`Type::char`]
640/// - [`Type::wide_char`]
641/// - [`Type::int`], [`Type::named_int`]
642/// - [`Type::float`], [`Type::named_float`]
643/// - [`Type::array`]
644/// - [`Type::enumeration`]
645/// - [`Type::structure`]
646/// - [`Type::named_type`], [`Type::named_type_from_type`]
647/// - [`Type::function`], [`Type::function_with_opts`]
648/// - [`Type::pointer`], [`Type::const_pointer`], [`Type::pointer_of_width`], [`Type::pointer_with_options`]
649///
650/// # Example
651///
652/// As an example, defining a _named_ type within a [`BinaryView`]:
653///
654/// ```no_run
655/// # use binaryninja::types::Type;
656/// let bv = binaryninja::load("example.bin").unwrap();
657/// let my_custom_type_1 = Type::named_int(5, false, "my_w");
658/// let my_custom_type_2 = Type::int(5, false);
659/// bv.define_user_type("int_1", &my_custom_type_1);
660/// bv.define_user_type("int_2", &my_custom_type_2);
661/// ```
662#[repr(transparent)]
663pub struct Type {
664    pub handle: *mut BNType,
665}
666
667impl Type {
668    pub unsafe fn from_raw(handle: *mut BNType) -> Self {
669        debug_assert!(!handle.is_null());
670        Self { handle }
671    }
672
673    pub unsafe fn ref_from_raw(handle: *mut BNType) -> Ref<Self> {
674        debug_assert!(!handle.is_null());
675        Ref::new(Self { handle })
676    }
677
678    pub fn to_builder(&self) -> TypeBuilder {
679        TypeBuilder::new(self)
680    }
681
682    pub fn type_class(&self) -> TypeClass {
683        unsafe { BNGetTypeClass(self.handle) }
684    }
685
686    // TODO: We need to decide on a public type to represent type width.
687    // TODO: The api uses both `u64` and `usize`, pick one or a new type!
688    /// The size of the type in bytes.
689    pub fn width(&self) -> u64 {
690        unsafe { BNGetTypeWidth(self.handle) }
691    }
692
693    pub fn alignment(&self) -> usize {
694        unsafe { BNGetTypeAlignment(self.handle) }
695    }
696
697    pub fn is_signed(&self) -> Conf<bool> {
698        unsafe { BNIsTypeSigned(self.handle).into() }
699    }
700
701    pub fn integer_display_type(&self) -> IntegerDisplayType {
702        unsafe { BNGetIntegerTypeDisplayType(self.handle) }
703    }
704
705    pub fn is_const(&self) -> Conf<bool> {
706        unsafe { BNIsTypeConst(self.handle).into() }
707    }
708
709    pub fn is_volatile(&self) -> Conf<bool> {
710        unsafe { BNIsTypeVolatile(self.handle).into() }
711    }
712
713    pub fn is_floating_point(&self) -> bool {
714        unsafe { BNIsTypeFloatingPoint(self.handle) }
715    }
716
717    pub fn child_type(&self) -> Option<Conf<Ref<Type>>> {
718        let raw_target = unsafe { BNGetChildType(self.handle) };
719        match raw_target.type_.is_null() {
720            false => Some(Conf::<Ref<Type>>::from_owned_raw(raw_target)),
721            true => None,
722        }
723    }
724
725    /// This is an alias for [`Self::child_type`].
726    pub fn target(&self) -> Option<Conf<Ref<Type>>> {
727        self.child_type()
728    }
729
730    /// This is an alias for [`Self::child_type`].
731    pub fn element_type(&self) -> Option<Conf<Ref<Type>>> {
732        self.child_type()
733    }
734
735    /// This is an alias for [`Self::child_type`].
736    pub fn return_value(&self) -> Option<Conf<Ref<Type>>> {
737        self.child_type()
738    }
739
740    pub fn calling_convention(&self) -> Option<Conf<Ref<CoreCallingConvention>>> {
741        let convention_confidence = unsafe { BNGetTypeCallingConvention(self.handle) };
742        match convention_confidence.convention.is_null() {
743            false => Some(Conf::<Ref<CoreCallingConvention>>::from_owned_raw(
744                convention_confidence,
745            )),
746            true => None,
747        }
748    }
749
750    pub fn parameters(&self) -> Option<Vec<FunctionParameter>> {
751        unsafe {
752            let mut count = 0;
753            let raw_parameters_ptr = BNGetTypeParameters(self.handle, &mut count);
754            match raw_parameters_ptr.is_null() {
755                false => {
756                    let raw_parameters = std::slice::from_raw_parts(raw_parameters_ptr, count);
757                    let parameters = raw_parameters
758                        .iter()
759                        .map(FunctionParameter::from_raw)
760                        .collect();
761                    BNFreeTypeParameterList(raw_parameters_ptr, count);
762                    Some(parameters)
763                }
764                true => None,
765            }
766        }
767    }
768
769    pub fn has_variable_arguments(&self) -> Conf<bool> {
770        unsafe { BNTypeHasVariableArguments(self.handle).into() }
771    }
772
773    pub fn can_return(&self) -> Conf<bool> {
774        unsafe { BNFunctionTypeCanReturn(self.handle).into() }
775    }
776
777    pub fn pure(&self) -> Conf<bool> {
778        unsafe { BNIsTypePure(self.handle).into() }
779    }
780
781    // TODO: This naming is problematic... rename to `as_structure`?
782    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
783    pub fn get_structure(&self) -> Option<Ref<Structure>> {
784        let raw_struct_ptr = unsafe { BNGetTypeStructure(self.handle) };
785        match raw_struct_ptr.is_null() {
786            false => Some(unsafe { Structure::ref_from_raw(raw_struct_ptr) }),
787            true => None,
788        }
789    }
790
791    // TODO: This naming is problematic... rename to `as_enumeration`?
792    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
793    pub fn get_enumeration(&self) -> Option<Ref<Enumeration>> {
794        let raw_enum_ptr = unsafe { BNGetTypeEnumeration(self.handle) };
795        match raw_enum_ptr.is_null() {
796            false => Some(unsafe { Enumeration::ref_from_raw(raw_enum_ptr) }),
797            true => None,
798        }
799    }
800
801    // TODO: This naming is problematic... rename to `as_named_type_reference`?
802    // TODO: We wouldn't need these sort of functions if we destructured `Type`...
803    pub fn get_named_type_reference(&self) -> Option<Ref<NamedTypeReference>> {
804        let raw_type_ref_ptr = unsafe { BNGetTypeNamedTypeReference(self.handle) };
805        match raw_type_ref_ptr.is_null() {
806            false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
807            true => None,
808        }
809    }
810
811    pub fn count(&self) -> u64 {
812        unsafe { BNGetTypeElementCount(self.handle) }
813    }
814
815    pub fn offset(&self) -> u64 {
816        unsafe { BNGetTypeOffset(self.handle) }
817    }
818
819    pub fn stack_adjustment(&self) -> Conf<i64> {
820        unsafe { BNGetTypeStackAdjustment(self.handle).into() }
821    }
822
823    pub fn registered_name(&self) -> Option<Ref<NamedTypeReference>> {
824        let raw_type_ref_ptr = unsafe { BNGetRegisteredTypeName(self.handle) };
825        match raw_type_ref_ptr.is_null() {
826            false => Some(unsafe { NamedTypeReference::ref_from_raw(raw_type_ref_ptr) }),
827            true => None,
828        }
829    }
830
831    pub fn pointer_base_type(&self) -> BNPointerBaseType {
832        unsafe { BNTypeGetPointerBaseType(self.handle) }
833    }
834
835    pub fn pointer_base_offset(&self) -> i64 {
836        unsafe { BNTypeGetPointerBaseOffset(self.handle) }
837    }
838
839    // TODO : This and properties
840    // pub fn tokens(&self) -> ? {}
841
842    pub fn void() -> Ref<Self> {
843        unsafe { Self::ref_from_raw(BNCreateVoidType()) }
844    }
845
846    pub fn bool() -> Ref<Self> {
847        unsafe { Self::ref_from_raw(BNCreateBoolType()) }
848    }
849
850    pub fn char() -> Ref<Self> {
851        Self::int(1, true)
852    }
853
854    pub fn wide_char(width: usize) -> Ref<Self> {
855        unsafe { Self::ref_from_raw(BNCreateWideCharType(width, c"".as_ptr())) }
856    }
857
858    pub fn int(width: usize, is_signed: bool) -> Ref<Self> {
859        let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
860        unsafe { Self::ref_from_raw(BNCreateIntegerType(width, &mut is_signed, c"".as_ptr())) }
861    }
862
863    pub fn named_int(width: usize, is_signed: bool, alt_name: &str) -> Ref<Self> {
864        let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into();
865        let alt_name = alt_name.to_cstr();
866
867        unsafe {
868            Self::ref_from_raw(BNCreateIntegerType(
869                width,
870                &mut is_signed,
871                alt_name.as_ptr(),
872            ))
873        }
874    }
875
876    pub fn float(width: usize) -> Ref<Self> {
877        unsafe { Self::ref_from_raw(BNCreateFloatType(width, c"".as_ptr())) }
878    }
879
880    pub fn named_float(width: usize, alt_name: &str) -> Ref<Self> {
881        let alt_name = alt_name.to_cstr();
882        unsafe { Self::ref_from_raw(BNCreateFloatType(width, alt_name.as_ptr())) }
883    }
884
885    pub fn array<'a, T: Into<Conf<&'a Type>>>(ty: T, count: u64) -> Ref<Self> {
886        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
887        unsafe { Self::ref_from_raw(BNCreateArrayType(&owned_raw_ty, count)) }
888    }
889
890    /// ## NOTE
891    ///
892    /// 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.
893    ///
894    /// For simplicity's sake, that convention isn't followed, and you can query [`Architecture::default_integer_size`] if you need to.
895    pub fn enumeration<T: Into<Conf<bool>>>(
896        enumeration: &Enumeration,
897        width: NonZeroUsize,
898        is_signed: T,
899    ) -> Ref<Self> {
900        unsafe {
901            Self::ref_from_raw(BNCreateEnumerationType(
902                // TODO: We pass nullptr arch, really we should not even be passing arch.
903                std::ptr::null_mut(),
904                enumeration.handle,
905                width.get(),
906                &mut is_signed.into().into(),
907            ))
908        }
909    }
910
911    pub fn structure(structure: &Structure) -> Ref<Self> {
912        unsafe { Self::ref_from_raw(BNCreateStructureType(structure.handle)) }
913    }
914
915    pub fn named_type(type_reference: &NamedTypeReference) -> Ref<Self> {
916        let mut is_const = Conf::new(false, MIN_CONFIDENCE).into();
917        let mut is_volatile = Conf::new(false, MIN_CONFIDENCE).into();
918        unsafe {
919            Self::ref_from_raw(BNCreateNamedTypeReference(
920                type_reference.handle,
921                0,
922                1,
923                &mut is_const,
924                &mut is_volatile,
925            ))
926        }
927    }
928
929    pub fn named_type_from_type<T: Into<QualifiedName>>(name: T, t: &Type) -> Ref<Self> {
930        let mut raw_name = QualifiedName::into_raw(name.into());
931        // TODO: No id is present for this call?
932        let id = c"";
933
934        let result = unsafe {
935            Self::ref_from_raw(BNCreateNamedTypeReferenceFromTypeAndId(
936                id.as_ptr(),
937                &mut raw_name,
938                t.handle,
939            ))
940        };
941        QualifiedName::free_raw(raw_name);
942        result
943    }
944
945    // TODO: FunctionBuilder
946    pub fn function<'a, T: Into<Conf<&'a Type>>>(
947        return_type: T,
948        parameters: Vec<FunctionParameter>,
949        variable_arguments: bool,
950    ) -> Ref<Self> {
951        let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
952        let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
953        let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
954        let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
955
956        let mut raw_calling_convention: BNCallingConventionWithConfidence =
957            BNCallingConventionWithConfidence {
958                convention: std::ptr::null_mut(),
959                confidence: MIN_CONFIDENCE,
960            };
961
962        let mut stack_adjust = Conf::new(0, MIN_CONFIDENCE).into();
963        let mut raw_parameters = parameters
964            .into_iter()
965            .map(FunctionParameter::into_raw)
966            .collect::<Vec<_>>();
967        let reg_stack_adjust_regs = std::ptr::null_mut();
968        let reg_stack_adjust_values = std::ptr::null_mut();
969
970        let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
971            regs: std::ptr::null_mut(),
972            count: 0,
973            confidence: 0,
974        };
975
976        let result = unsafe {
977            Self::ref_from_raw(BNCreateFunctionType(
978                &mut owned_raw_return_type,
979                &mut raw_calling_convention,
980                raw_parameters.as_mut_ptr(),
981                raw_parameters.len(),
982                &mut variable_arguments,
983                &mut can_return,
984                &mut stack_adjust,
985                reg_stack_adjust_regs,
986                reg_stack_adjust_values,
987                0,
988                &mut return_regs,
989                BNNameType::NoNameType,
990                &mut pure,
991            ))
992        };
993
994        for raw_param in raw_parameters {
995            FunctionParameter::free_raw(raw_param);
996        }
997
998        result
999    }
1000
1001    // TODO: FunctionBuilder
1002    pub fn function_with_opts<
1003        'a,
1004        T: Into<Conf<&'a Type>>,
1005        C: Into<Conf<Ref<CoreCallingConvention>>>,
1006    >(
1007        return_type: T,
1008        parameters: &[FunctionParameter],
1009        variable_arguments: bool,
1010        calling_convention: C,
1011        stack_adjust: Conf<i64>,
1012    ) -> Ref<Self> {
1013        let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
1014        let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
1015        let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
1016        let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
1017
1018        let mut owned_raw_calling_convention =
1019            Conf::<Ref<CoreCallingConvention>>::into_owned_raw(&calling_convention.into());
1020
1021        let mut stack_adjust = stack_adjust.into();
1022        let mut raw_parameters = parameters
1023            .iter()
1024            .cloned()
1025            .map(FunctionParameter::into_raw)
1026            .collect::<Vec<_>>();
1027
1028        // TODO: Update type signature and include these (will be a breaking change)
1029        let reg_stack_adjust_regs = std::ptr::null_mut();
1030        let reg_stack_adjust_values = std::ptr::null_mut();
1031
1032        let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
1033            regs: std::ptr::null_mut(),
1034            count: 0,
1035            confidence: 0,
1036        };
1037
1038        let result = unsafe {
1039            Self::ref_from_raw(BNCreateFunctionType(
1040                &mut owned_raw_return_type,
1041                &mut owned_raw_calling_convention,
1042                raw_parameters.as_mut_ptr(),
1043                raw_parameters.len(),
1044                &mut variable_arguments,
1045                &mut can_return,
1046                &mut stack_adjust,
1047                reg_stack_adjust_regs,
1048                reg_stack_adjust_values,
1049                0,
1050                &mut return_regs,
1051                BNNameType::NoNameType,
1052                &mut pure,
1053            ))
1054        };
1055
1056        for raw_param in raw_parameters {
1057            FunctionParameter::free_raw(raw_param);
1058        }
1059
1060        result
1061    }
1062
1063    pub fn pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(arch: &A, ty: T) -> Ref<Self> {
1064        Self::pointer_with_options(arch, ty, false, false, None)
1065    }
1066
1067    pub fn const_pointer<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
1068        arch: &A,
1069        ty: T,
1070    ) -> Ref<Self> {
1071        Self::pointer_with_options(arch, ty, true, false, None)
1072    }
1073
1074    pub fn pointer_with_options<'a, A: Architecture, T: Into<Conf<&'a Type>>>(
1075        arch: &A,
1076        ty: T,
1077        is_const: bool,
1078        is_volatile: bool,
1079        ref_type: Option<ReferenceType>,
1080    ) -> Ref<Self> {
1081        let arch_pointer_size = arch.address_size();
1082        Self::pointer_of_width(ty, arch_pointer_size, is_const, is_volatile, ref_type)
1083    }
1084
1085    pub fn pointer_of_width<'a, T: Into<Conf<&'a Type>>>(
1086        ty: T,
1087        size: usize,
1088        is_const: bool,
1089        is_volatile: bool,
1090        ref_type: Option<ReferenceType>,
1091    ) -> Ref<Self> {
1092        let mut is_const = Conf::new(is_const, MAX_CONFIDENCE).into();
1093        let mut is_volatile = Conf::new(is_volatile, MAX_CONFIDENCE).into();
1094        let owned_raw_ty = Conf::<&Type>::into_raw(ty.into());
1095        unsafe {
1096            Self::ref_from_raw(BNCreatePointerTypeOfWidth(
1097                size,
1098                &owned_raw_ty,
1099                &mut is_const,
1100                &mut is_volatile,
1101                ref_type.unwrap_or(ReferenceType::PointerReferenceType),
1102            ))
1103        }
1104    }
1105
1106    pub fn generate_auto_demangled_type_id<T: Into<QualifiedName>>(name: T) -> String {
1107        let mut raw_name = QualifiedName::into_raw(name.into());
1108        let type_id =
1109            unsafe { BnString::into_string(BNGenerateAutoDemangledTypeId(&mut raw_name)) };
1110        QualifiedName::free_raw(raw_name);
1111        type_id
1112    }
1113}
1114
1115impl Display for Type {
1116    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1117        write!(f, "{}", unsafe {
1118            BnString::into_string(BNGetTypeString(
1119                self.handle,
1120                std::ptr::null_mut(),
1121                BNTokenEscapingType::NoTokenEscapingType,
1122            ))
1123        })
1124    }
1125}
1126
1127impl Debug for Type {
1128    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1129        // You might be tempted to rip this atrocity out and make this more "sensible". READ BELOW!
1130        // Type is a one-size fits all structure, these are actually its fields! If we wanted to
1131        // omit some fields for different type classes, what you really want to do is implement your
1132        // own formatter. This is supposed to represent the structure entirely, it's not supposed to be pretty!
1133        f.debug_struct("Type")
1134            .field("type_class", &self.type_class())
1135            .field("width", &self.width())
1136            .field("alignment", &self.alignment())
1137            .field("is_signed", &self.is_signed())
1138            .field("is_const", &self.is_const())
1139            .field("is_volatile", &self.is_volatile())
1140            .field("child_type", &self.child_type())
1141            .field("calling_convention", &self.calling_convention())
1142            .field("parameters", &self.parameters())
1143            .field("has_variable_arguments", &self.has_variable_arguments())
1144            .field("can_return", &self.can_return())
1145            .field("pure", &self.pure())
1146            .field("get_structure", &self.get_structure())
1147            .field("get_enumeration", &self.get_enumeration())
1148            .field("get_named_type_reference", &self.get_named_type_reference())
1149            .field("count", &self.count())
1150            .field("offset", &self.offset())
1151            .field("stack_adjustment", &self.stack_adjustment())
1152            .field("registered_name", &self.registered_name())
1153            .finish()
1154    }
1155}
1156
1157impl PartialEq for Type {
1158    fn eq(&self, other: &Self) -> bool {
1159        unsafe { BNTypesEqual(self.handle, other.handle) }
1160    }
1161}
1162
1163impl Eq for Type {}
1164
1165impl Hash for Type {
1166    fn hash<H: Hasher>(&self, state: &mut H) {
1167        self.handle.hash(state);
1168    }
1169}
1170
1171unsafe impl Send for Type {}
1172unsafe impl Sync for Type {}
1173
1174unsafe impl RefCountable for Type {
1175    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
1176        Self::ref_from_raw(BNNewTypeReference(handle.handle))
1177    }
1178
1179    unsafe fn dec_ref(handle: &Self) {
1180        BNFreeType(handle.handle);
1181    }
1182}
1183
1184impl ToOwned for Type {
1185    type Owned = Ref<Self>;
1186
1187    fn to_owned(&self) -> Self::Owned {
1188        unsafe { RefCountable::inc_ref(self) }
1189    }
1190}
1191
1192impl CoreArrayProvider for Type {
1193    type Raw = *mut BNType;
1194    type Context = ();
1195    type Wrapped<'a> = &'a Self;
1196}
1197
1198unsafe impl CoreArrayProviderInner for Type {
1199    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
1200        BNFreeTypeList(raw, count)
1201    }
1202
1203    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
1204        // TODO: This is assuming &'a Type is &*mut BNType
1205        std::mem::transmute(raw)
1206    }
1207}
1208
1209#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1210pub struct FunctionParameter {
1211    pub ty: Conf<Ref<Type>>,
1212    pub name: String,
1213    pub location: Option<Variable>,
1214}
1215
1216impl FunctionParameter {
1217    pub(crate) fn from_raw(value: &BNFunctionParameter) -> Self {
1218        // TODO: I copied this from the original `from_raw` function.
1219        // TODO: So this actually needs to be audited later.
1220        let name = if value.name.is_null() {
1221            if value.location.type_ == VariableSourceType::RegisterVariableSourceType {
1222                format!("reg_{}", value.location.storage)
1223            } else if value.location.type_ == VariableSourceType::StackVariableSourceType {
1224                format!("arg_{}", value.location.storage)
1225            } else {
1226                String::new()
1227            }
1228        } else {
1229            raw_to_string(value.name as *const _).unwrap()
1230        };
1231
1232        Self {
1233            ty: Conf::new(
1234                unsafe { Type::from_raw(value.type_).to_owned() },
1235                value.typeConfidence,
1236            ),
1237            name,
1238            location: match value.defaultLocation {
1239                false => Some(Variable::from(value.location)),
1240                true => None,
1241            },
1242        }
1243    }
1244
1245    #[allow(unused)]
1246    pub(crate) fn from_owned_raw(value: BNFunctionParameter) -> Self {
1247        let owned = Self::from_raw(&value);
1248        Self::free_raw(value);
1249        owned
1250    }
1251
1252    pub(crate) fn into_raw(value: Self) -> BNFunctionParameter {
1253        let bn_name = BnString::new(value.name);
1254        BNFunctionParameter {
1255            name: BnString::into_raw(bn_name),
1256            type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
1257            typeConfidence: value.ty.confidence,
1258            defaultLocation: value.location.is_none(),
1259            location: value.location.map(Into::into).unwrap_or_default(),
1260        }
1261    }
1262
1263    pub(crate) fn free_raw(value: BNFunctionParameter) {
1264        unsafe { BnString::free_raw(value.name) };
1265        let _ = unsafe { Type::ref_from_raw(value.type_) };
1266    }
1267
1268    pub fn new<T: Into<Conf<Ref<Type>>>>(ty: T, name: String, location: Option<Variable>) -> Self {
1269        Self {
1270            ty: ty.into(),
1271            name,
1272            location,
1273        }
1274    }
1275}
1276
1277#[derive(PartialEq, Eq, Hash)]
1278pub struct NamedTypeReference {
1279    pub(crate) handle: *mut BNNamedTypeReference,
1280}
1281
1282impl NamedTypeReference {
1283    pub(crate) unsafe fn from_raw(handle: *mut BNNamedTypeReference) -> Self {
1284        debug_assert!(!handle.is_null());
1285        Self { handle }
1286    }
1287
1288    pub(crate) unsafe fn ref_from_raw(handle: *mut BNNamedTypeReference) -> Ref<Self> {
1289        debug_assert!(!handle.is_null());
1290        Ref::new(Self { handle })
1291    }
1292
1293    /// Create an NTR to a type that did not come directly from a BinaryView's types list.
1294    /// That is to say, if you're referencing a new type you're GOING to add, use this.
1295    /// You should not assign type ids yourself, that is the responsibility of the BinaryView
1296    /// implementation after your types have been added. Just make sure the names match up and
1297    /// the core will do the id stuff for you.
1298    pub fn new<T: Into<QualifiedName>>(type_class: NamedTypeReferenceClass, name: T) -> Ref<Self> {
1299        let mut raw_name = QualifiedName::into_raw(name.into());
1300        let result = unsafe {
1301            Self::ref_from_raw(BNCreateNamedType(
1302                type_class,
1303                std::ptr::null(),
1304                &mut raw_name,
1305            ))
1306        };
1307        QualifiedName::free_raw(raw_name);
1308        result
1309    }
1310
1311    /// Create an NTR to a type with an existing type id, which generally means it came directly
1312    /// from a BinaryView's types list and its id was looked up using `BinaryView::get_type_id`.
1313    /// You should not assign type ids yourself: if you use this to reference a type you are going
1314    /// to create but have not yet created, you may run into problems when giving your types to
1315    /// a BinaryView.
1316    pub fn new_with_id<T: Into<QualifiedName>>(
1317        type_class: NamedTypeReferenceClass,
1318        type_id: &str,
1319        name: T,
1320    ) -> Ref<Self> {
1321        let type_id = type_id.to_cstr();
1322        let mut raw_name = QualifiedName::into_raw(name.into());
1323        let result = unsafe {
1324            Self::ref_from_raw(BNCreateNamedType(
1325                type_class,
1326                type_id.as_ref().as_ptr() as _,
1327                &mut raw_name,
1328            ))
1329        };
1330        QualifiedName::free_raw(raw_name);
1331        result
1332    }
1333
1334    pub fn name(&self) -> QualifiedName {
1335        let raw_name = unsafe { BNGetTypeReferenceName(self.handle) };
1336        QualifiedName::from_owned_raw(raw_name)
1337    }
1338
1339    pub fn id(&self) -> String {
1340        unsafe { BnString::into_string(BNGetTypeReferenceId(self.handle)) }
1341    }
1342
1343    pub fn class(&self) -> NamedTypeReferenceClass {
1344        unsafe { BNGetTypeReferenceClass(self.handle) }
1345    }
1346
1347    fn target_helper(&self, bv: &BinaryView, visited: &mut HashSet<String>) -> Option<Ref<Type>> {
1348        let ty = bv.type_by_id(&self.id())?;
1349        match ty.type_class() {
1350            TypeClass::NamedTypeReferenceClass => {
1351                // Recurse into the NTR type until we get the target type.
1352                let ntr = ty
1353                    .get_named_type_reference()
1354                    .expect("NTR type class should always have a valid NTR");
1355                match visited.insert(ntr.id()) {
1356                    true => ntr.target_helper(bv, visited),
1357                    // Cyclic reference, return None.
1358                    false => None,
1359                }
1360            }
1361            // Found target type
1362            _ => Some(ty),
1363        }
1364    }
1365
1366    /// Type referenced by this [`NamedTypeReference`].
1367    ///
1368    /// Will return `None` if the reference is cyclic, or the target type does not exist.
1369    pub fn target(&self, bv: &BinaryView) -> Option<Ref<Type>> {
1370        self.target_helper(bv, &mut HashSet::new())
1371    }
1372}
1373
1374impl ToOwned for NamedTypeReference {
1375    type Owned = Ref<Self>;
1376
1377    fn to_owned(&self) -> Self::Owned {
1378        unsafe { RefCountable::inc_ref(self) }
1379    }
1380}
1381
1382unsafe impl RefCountable for NamedTypeReference {
1383    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
1384        Self::ref_from_raw(BNNewNamedTypeReference(handle.handle))
1385    }
1386
1387    unsafe fn dec_ref(handle: &Self) {
1388        BNFreeNamedTypeReference(handle.handle)
1389    }
1390}
1391
1392impl Debug for NamedTypeReference {
1393    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1394        write!(f, "{} (id: {})", self.name(), self.id())
1395    }
1396}
1397
1398#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1399pub struct QualifiedNameAndType {
1400    pub name: QualifiedName,
1401    pub ty: Ref<Type>,
1402}
1403
1404impl QualifiedNameAndType {
1405    pub(crate) fn from_raw(value: &BNQualifiedNameAndType) -> Self {
1406        Self {
1407            name: QualifiedName::from_raw(&value.name),
1408            ty: unsafe { Type::from_raw(value.type_).to_owned() },
1409        }
1410    }
1411
1412    pub(crate) fn from_owned_raw(value: BNQualifiedNameAndType) -> Self {
1413        let owned = Self::from_raw(&value);
1414        Self::free_raw(value);
1415        owned
1416    }
1417
1418    pub(crate) fn into_raw(value: Self) -> BNQualifiedNameAndType {
1419        BNQualifiedNameAndType {
1420            name: QualifiedName::into_raw(value.name),
1421            type_: unsafe { Ref::into_raw(value.ty).handle },
1422        }
1423    }
1424
1425    pub(crate) fn free_raw(value: BNQualifiedNameAndType) {
1426        QualifiedName::free_raw(value.name);
1427        let _ = unsafe { Type::ref_from_raw(value.type_) };
1428    }
1429
1430    pub fn new(name: QualifiedName, ty: Ref<Type>) -> Self {
1431        Self { name, ty }
1432    }
1433}
1434
1435impl<T> From<(T, Ref<Type>)> for QualifiedNameAndType
1436where
1437    T: Into<QualifiedName>,
1438{
1439    fn from(value: (T, Ref<Type>)) -> Self {
1440        Self {
1441            name: value.0.into(),
1442            ty: value.1,
1443        }
1444    }
1445}
1446
1447impl<T> From<(T, &Type)> for QualifiedNameAndType
1448where
1449    T: Into<QualifiedName>,
1450{
1451    fn from(value: (T, &Type)) -> Self {
1452        let ty = value.1.to_owned();
1453        Self {
1454            name: value.0.into(),
1455            ty,
1456        }
1457    }
1458}
1459
1460impl CoreArrayProvider for QualifiedNameAndType {
1461    type Raw = BNQualifiedNameAndType;
1462    type Context = ();
1463    type Wrapped<'a> = Self;
1464}
1465
1466unsafe impl CoreArrayProviderInner for QualifiedNameAndType {
1467    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
1468        BNFreeTypeAndNameList(raw, count);
1469    }
1470
1471    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
1472        QualifiedNameAndType::from_raw(raw)
1473    }
1474}
1475
1476#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1477pub struct QualifiedNameTypeAndId {
1478    pub name: QualifiedName,
1479    pub ty: Ref<Type>,
1480    pub id: String,
1481}
1482
1483impl QualifiedNameTypeAndId {
1484    pub(crate) fn from_raw(value: &BNQualifiedNameTypeAndId) -> Self {
1485        Self {
1486            name: QualifiedName::from_raw(&value.name),
1487            ty: unsafe { Type::from_raw(value.type_) }.to_owned(),
1488            id: raw_to_string(value.id).unwrap(),
1489        }
1490    }
1491
1492    #[allow(unused)]
1493    pub(crate) fn from_owned_raw(value: BNQualifiedNameTypeAndId) -> Self {
1494        let owned = Self::from_raw(&value);
1495        Self::free_raw(value);
1496        owned
1497    }
1498
1499    pub(crate) fn into_raw(value: Self) -> BNQualifiedNameTypeAndId {
1500        let bn_id = BnString::new(value.id);
1501        BNQualifiedNameTypeAndId {
1502            name: QualifiedName::into_raw(value.name),
1503            id: BnString::into_raw(bn_id),
1504            type_: unsafe { Ref::into_raw(value.ty) }.handle,
1505        }
1506    }
1507
1508    pub(crate) fn free_raw(value: BNQualifiedNameTypeAndId) {
1509        QualifiedName::free_raw(value.name);
1510        let _ = unsafe { Type::ref_from_raw(value.type_) };
1511        let _ = unsafe { BnString::from_raw(value.id) };
1512    }
1513}
1514
1515impl CoreArrayProvider for QualifiedNameTypeAndId {
1516    type Raw = BNQualifiedNameTypeAndId;
1517    type Context = ();
1518    type Wrapped<'a> = QualifiedNameTypeAndId;
1519}
1520
1521unsafe impl CoreArrayProviderInner for QualifiedNameTypeAndId {
1522    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
1523        BNFreeTypeIdList(raw, count);
1524    }
1525
1526    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
1527        QualifiedNameTypeAndId::from_raw(raw)
1528    }
1529}
1530
1531// TODO: Document how this type is used for many different purposes. (this is literally (string, type))
1532// TODO: Ex. the name might be the parser it came from
1533// TODO: Ex. the name might be the param name for an intrinsic input
1534// TODO: Should we make new types for each varying use case?
1535#[derive(Debug, Clone, Eq, PartialEq, Hash)]
1536pub struct NameAndType {
1537    pub name: String,
1538    pub ty: Conf<Ref<Type>>,
1539}
1540
1541impl NameAndType {
1542    pub(crate) fn from_raw(value: &BNNameAndType) -> Self {
1543        Self {
1544            // TODO: I dislike using this function here.
1545            name: raw_to_string(value.name as *mut _).unwrap(),
1546            ty: Conf::new(
1547                unsafe { Type::from_raw(value.type_).to_owned() },
1548                value.typeConfidence,
1549            ),
1550        }
1551    }
1552
1553    #[allow(unused)]
1554    pub(crate) fn from_owned_raw(value: BNNameAndType) -> Self {
1555        let owned = Self::from_raw(&value);
1556        Self::free_raw(value);
1557        owned
1558    }
1559
1560    pub(crate) fn into_raw(value: Self) -> BNNameAndType {
1561        let bn_name = BnString::new(value.name);
1562        BNNameAndType {
1563            name: BnString::into_raw(bn_name),
1564            type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
1565            typeConfidence: value.ty.confidence,
1566        }
1567    }
1568
1569    pub(crate) fn free_raw(value: BNNameAndType) {
1570        unsafe { BnString::free_raw(value.name) };
1571        let _ = unsafe { Type::ref_from_raw(value.type_) };
1572    }
1573
1574    pub fn new(name: impl Into<String>, ty: Conf<Ref<Type>>) -> Self {
1575        Self {
1576            name: name.into(),
1577            ty,
1578        }
1579    }
1580}
1581
1582impl CoreArrayProvider for NameAndType {
1583    type Raw = BNNameAndType;
1584    type Context = ();
1585    type Wrapped<'a> = Self;
1586}
1587
1588unsafe impl CoreArrayProviderInner for NameAndType {
1589    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
1590        BNFreeNameAndTypeList(raw, count);
1591    }
1592
1593    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
1594        NameAndType::from_raw(raw)
1595    }
1596}