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