Skip to main content

inkwell/types/
struct_type.rs

1use llvm_sys::core::{
2    LLVMConstNamedStruct, LLVMCountStructElementTypes, LLVMGetStructElementTypes, LLVMGetStructName,
3    LLVMIsOpaqueStruct, LLVMIsPackedStruct, LLVMStructGetTypeAtIndex, LLVMStructSetBody,
4};
5use llvm_sys::prelude::{LLVMTypeRef, LLVMValueRef};
6
7use std::ffi::CStr;
8use std::fmt::{self, Display};
9use std::mem::forget;
10
11use crate::context::ContextRef;
12use crate::support::LLVMString;
13use crate::types::enums::BasicMetadataTypeEnum;
14use crate::types::traits::AsTypeRef;
15use crate::types::{ArrayType, BasicTypeEnum, FunctionType, PointerType, Type};
16use crate::values::{ArrayValue, AsValueRef, BasicValueEnum, IntValue, StructValue};
17use crate::AddressSpace;
18
19/// A `StructType` is the type of a heterogeneous container of types.
20#[derive(Debug, PartialEq, Eq, Clone, Copy)]
21pub struct StructType<'ctx> {
22    struct_type: Type<'ctx>,
23}
24
25impl<'ctx> StructType<'ctx> {
26    /// Create `StructType` from [`LLVMTypeRef`]
27    ///
28    /// # Safety
29    /// Undefined behavior, if referenced type isn't struct type
30    pub unsafe fn new(struct_type: LLVMTypeRef) -> Self {
31        assert!(!struct_type.is_null());
32
33        StructType {
34            struct_type: Type::new(struct_type),
35        }
36    }
37
38    /// Gets the type of a field belonging to this `StructType`.
39    ///
40    /// # Example
41    ///
42    /// ```no_run
43    /// use inkwell::context::Context;
44    ///
45    /// let context = Context::create();
46    /// let f32_type = context.f32_type();
47    /// let struct_type = context.struct_type(&[f32_type.into()], false);
48    ///
49    /// assert_eq!(struct_type.get_field_type_at_index(0).unwrap().into_float_type(), f32_type);
50    /// ```
51    pub fn get_field_type_at_index(self, index: u32) -> Option<BasicTypeEnum<'ctx>> {
52        // LLVM doesn't seem to just return null if opaque.
53        // TODO: One day, with SubTypes (& maybe specialization?) we could just
54        // impl this method for non opaque structs only
55        if self.is_opaque() {
56            return None;
57        }
58
59        // OoB indexing seems to be unchecked and therefore is UB
60        if index >= self.count_fields() {
61            return None;
62        }
63
64        Some(unsafe { self.get_field_type_at_index_unchecked(index) })
65    }
66
67    /// Gets the type of a field belonging to this `StructType`.
68    ///
69    /// # Safety
70    ///
71    /// The index must be less than [StructType::count_fields] and the struct must not be opaque.
72    pub unsafe fn get_field_type_at_index_unchecked(self, index: u32) -> BasicTypeEnum<'ctx> {
73        unsafe { BasicTypeEnum::new(LLVMStructGetTypeAtIndex(self.as_type_ref(), index)) }
74    }
75
76    /// Creates a `StructValue` based on this `StructType`'s definition.
77    ///
78    /// # Example
79    ///
80    /// ```no_run
81    /// use inkwell::context::Context;
82    ///
83    /// let context = Context::create();
84    /// let f32_type = context.f32_type();
85    /// let f32_zero = f32_type.const_float(0.);
86    /// let struct_type = context.struct_type(&[f32_type.into()], false);
87    /// let struct_val = struct_type.const_named_struct(&[f32_zero.into()]);
88    /// ```
89    pub fn const_named_struct(self, values: &[BasicValueEnum<'ctx>]) -> StructValue<'ctx> {
90        let mut args: Vec<LLVMValueRef> = values.iter().map(|val| val.as_value_ref()).collect();
91        unsafe {
92            StructValue::new(LLVMConstNamedStruct(
93                self.as_type_ref(),
94                args.as_mut_ptr(),
95                args.len() as u32,
96            ))
97        }
98    }
99
100    /// Creates a constant zero value of this `StructType`.
101    ///
102    /// # Example
103    ///
104    /// ```no_run
105    /// use inkwell::context::Context;
106    ///
107    /// let context = Context::create();
108    /// let f32_type = context.f32_type();
109    /// let struct_type = context.struct_type(&[f32_type.into(), f32_type.into()], false);
110    /// let struct_zero = struct_type.const_zero();
111    /// ```
112    pub fn const_zero(self) -> StructValue<'ctx> {
113        unsafe { StructValue::new(self.struct_type.const_zero()) }
114    }
115
116    // TODO: impl it only for StructType<T*>?
117    /// Gets the size of this `StructType`. Value may vary depending on the target architecture.
118    ///
119    /// # Example
120    ///
121    /// ```no_run
122    /// use inkwell::context::Context;
123    ///
124    /// let context = Context::create();
125    /// let f32_type = context.f32_type();
126    /// let f32_struct_type = context.struct_type(&[f32_type.into()], false);
127    /// let f32_struct_type_size = f32_struct_type.size_of();
128    /// ```
129    pub fn size_of(self) -> Option<IntValue<'ctx>> {
130        self.struct_type.size_of()
131    }
132
133    /// Gets a reference to the `Context` this `StructType` was created in.
134    ///
135    /// # Example
136    ///
137    /// ```no_run
138    /// use inkwell::context::Context;
139    ///
140    /// let context = Context::create();
141    /// let f32_type = context.f32_type();
142    /// let struct_type = context.struct_type(&[f32_type.into(), f32_type.into()], false);
143    ///
144    /// assert_eq!(struct_type.get_context(), context);
145    /// ```
146    pub fn get_context(self) -> ContextRef<'ctx> {
147        self.struct_type.get_context()
148    }
149
150    /// Gets this `StructType`'s name.
151    ///
152    /// # Example
153    ///
154    /// ```no_run
155    /// use inkwell::context::Context;
156    ///
157    /// let context = Context::create();
158    /// let f32_type = context.f32_type();
159    /// let struct_type = context.opaque_struct_type("opaque_struct");
160    ///
161    /// assert_eq!(struct_type.get_name().unwrap().to_str().unwrap(), "opaque_struct");
162    /// ```
163    pub fn get_name(&self) -> Option<&CStr> {
164        let name = unsafe { LLVMGetStructName(self.as_type_ref()) };
165
166        if name.is_null() {
167            return None;
168        }
169
170        let c_str = unsafe { CStr::from_ptr(name) };
171
172        Some(c_str)
173    }
174
175    /// Creates a `PointerType` with this `StructType` for its element type.
176    ///
177    /// # Example
178    ///
179    /// ```no_run
180    /// use inkwell::AddressSpace;
181    /// use inkwell::context::Context;
182    ///
183    /// let context = Context::create();
184    /// let f32_type = context.f32_type();
185    /// let struct_type = context.struct_type(&[f32_type.into(), f32_type.into()], false);
186    /// let struct_ptr_type = struct_type.ptr_type(AddressSpace::default());
187    ///
188    /// #[cfg(feature = "typed-pointers")]
189    /// assert_eq!(struct_ptr_type.get_element_type().into_struct_type(), struct_type);
190    /// ```
191    #[cfg_attr(
192        any(
193            all(feature = "llvm15-0", not(feature = "typed-pointers")),
194            all(feature = "llvm16-0", not(feature = "typed-pointers")),
195            feature = "llvm17-0",
196            feature = "llvm18-1",
197            feature = "llvm19-1",
198            feature = "llvm20-1",
199            feature = "llvm21-1",
200        ),
201        deprecated(
202            note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead."
203        )
204    )]
205    pub fn ptr_type(self, address_space: AddressSpace) -> PointerType<'ctx> {
206        self.struct_type.ptr_type(address_space)
207    }
208
209    /// Creates a `FunctionType` with this `StructType` for its return type.
210    ///
211    /// # Example
212    ///
213    /// ```no_run
214    /// use inkwell::context::Context;
215    ///
216    /// let context = Context::create();
217    /// let f32_type = context.f32_type();
218    /// let struct_type = context.struct_type(&[f32_type.into(), f32_type.into()], false);
219    /// let fn_type = struct_type.fn_type(&[], false);
220    /// ```
221    pub fn fn_type(self, param_types: &[BasicMetadataTypeEnum<'ctx>], is_var_args: bool) -> FunctionType<'ctx> {
222        self.struct_type.fn_type(param_types, is_var_args)
223    }
224
225    /// Creates an `ArrayType` with this `StructType` for its element type.
226    ///
227    /// # Example
228    ///
229    /// ```no_run
230    /// use inkwell::context::Context;
231    ///
232    /// let context = Context::create();
233    /// let f32_type = context.f32_type();
234    /// let struct_type = context.struct_type(&[f32_type.into(), f32_type.into()], false);
235    /// let struct_array_type = struct_type.array_type(3);
236    ///
237    /// assert_eq!(struct_array_type.len(), 3);
238    /// assert_eq!(struct_array_type.get_element_type().into_struct_type(), struct_type);
239    /// ```
240    pub fn array_type(self, size: u32) -> ArrayType<'ctx> {
241        self.struct_type.array_type(size)
242    }
243
244    /// Determines whether or not a `StructType` is packed.
245    ///
246    /// # Example
247    ///
248    /// ```no_run
249    /// use inkwell::context::Context;
250    ///
251    /// let context = Context::create();
252    /// let f32_type = context.f32_type();
253    /// let struct_type = context.struct_type(&[f32_type.into(), f32_type.into()], false);
254    ///
255    /// assert!(struct_type.is_packed());
256    /// ```
257    pub fn is_packed(self) -> bool {
258        unsafe { LLVMIsPackedStruct(self.as_type_ref()) == 1 }
259    }
260
261    /// Determines whether or not a `StructType` is opaque.
262    ///
263    /// # Example
264    ///
265    /// ```no_run
266    /// use inkwell::context::Context;
267    ///
268    /// let context = Context::create();
269    /// let f32_type = context.f32_type();
270    /// let struct_type = context.opaque_struct_type("opaque_struct");
271    ///
272    /// assert!(struct_type.is_opaque());
273    /// ```
274    pub fn is_opaque(self) -> bool {
275        unsafe { LLVMIsOpaqueStruct(self.as_type_ref()) == 1 }
276    }
277
278    /// Counts the number of field types.
279    ///
280    /// # Example
281    ///
282    /// ```no_run
283    /// use inkwell::context::Context;
284    ///
285    /// let context = Context::create();
286    /// let f32_type = context.f32_type();
287    /// let i8_type = context.i8_type();
288    /// let struct_type = context.struct_type(&[f32_type.into(), i8_type.into()], false);
289    ///
290    /// assert_eq!(struct_type.count_fields(), 2);
291    /// ```
292    pub fn count_fields(self) -> u32 {
293        unsafe { LLVMCountStructElementTypes(self.as_type_ref()) }
294    }
295
296    /// Gets this `StructType`'s field types.
297    ///
298    /// # Example
299    ///
300    /// ```no_run
301    /// use inkwell::context::Context;
302    ///
303    /// let context = Context::create();
304    /// let f32_type = context.f32_type();
305    /// let i8_type = context.i8_type();
306    /// let struct_type = context.struct_type(&[f32_type.into(), i8_type.into()], false);
307    ///
308    /// assert_eq!(struct_type.get_field_types(), &[f32_type.into(), i8_type.into()]);
309    /// ```
310    pub fn get_field_types(self) -> Vec<BasicTypeEnum<'ctx>> {
311        let count = self.count_fields();
312        let mut raw_vec: Vec<LLVMTypeRef> = Vec::with_capacity(count as usize);
313        let ptr = raw_vec.as_mut_ptr();
314
315        forget(raw_vec);
316
317        let raw_vec = unsafe {
318            LLVMGetStructElementTypes(self.as_type_ref(), ptr);
319
320            Vec::from_raw_parts(ptr, count as usize, count as usize)
321        };
322
323        raw_vec.iter().map(|val| unsafe { BasicTypeEnum::new(*val) }).collect()
324    }
325
326    /// Get a struct field iterator.
327    pub fn get_field_types_iter(self) -> FieldTypesIter<'ctx> {
328        FieldTypesIter {
329            st: self,
330            i: 0,
331            count: if self.is_opaque() { 0 } else { self.count_fields() },
332        }
333    }
334
335    /// Print the definition of a `StructType` to `LLVMString`.
336    pub fn print_to_string(self) -> LLVMString {
337        self.struct_type.print_to_string()
338    }
339
340    /// Creates an undefined instance of a `StructType`.
341    ///
342    /// # Example
343    ///
344    /// ```no_run
345    /// use inkwell::context::Context;
346    ///
347    /// let context = Context::create();
348    /// let f32_type = context.f32_type();
349    /// let i8_type = context.i8_type();
350    /// let struct_type = context.struct_type(&[f32_type.into(), i8_type.into()], false);
351    /// let struct_type_undef = struct_type.get_undef();
352    ///
353    /// assert!(struct_type_undef.is_undef());
354    /// ```
355    pub fn get_undef(self) -> StructValue<'ctx> {
356        unsafe { StructValue::new(self.struct_type.get_undef()) }
357    }
358
359    /// Creates a poison instance of a `StructType`.
360    ///
361    /// # Example
362    ///
363    /// ```no_run
364    /// use inkwell::context::Context;
365    /// use inkwell::values::AnyValue;
366    ///
367    /// let context = Context::create();
368    /// let f32_type = context.f32_type();
369    /// let i8_type = context.i8_type();
370    /// let struct_type = context.struct_type(&[f32_type.into(), i8_type.into()], false);
371    /// let struct_type_poison = struct_type.get_poison();
372    ///
373    /// assert!(struct_type_poison.is_poison());
374    /// ```
375    #[llvm_versions(12..)]
376    pub fn get_poison(self) -> StructValue<'ctx> {
377        unsafe { StructValue::new(self.struct_type.get_poison()) }
378    }
379
380    /// Defines the body of a `StructType`.
381    ///
382    /// If the struct is an opaque type, it will no longer be after this call.
383    ///
384    /// Resetting the `packed` state of a non-opaque struct type may not work.
385    ///
386    /// # Example
387    ///
388    /// ```no_run
389    /// use inkwell::context::Context;
390    ///
391    /// let context = Context::create();
392    /// let f32_type = context.f32_type();
393    /// let opaque_struct_type = context.opaque_struct_type("opaque_struct");
394    ///
395    /// opaque_struct_type.set_body(&[f32_type.into()], false);
396    ///
397    /// assert!(!opaque_struct_type.is_opaque());
398    /// ```
399    pub fn set_body(self, field_types: &[BasicTypeEnum<'ctx>], packed: bool) -> bool {
400        let is_opaque = self.is_opaque();
401        let mut field_types: Vec<LLVMTypeRef> = field_types.iter().map(|val| val.as_type_ref()).collect();
402        unsafe {
403            LLVMStructSetBody(
404                self.as_type_ref(),
405                field_types.as_mut_ptr(),
406                field_types.len() as u32,
407                packed as i32,
408            );
409        }
410
411        is_opaque
412    }
413
414    /// Creates a constant `ArrayValue`.
415    ///
416    /// # Example
417    ///
418    /// ```no_run
419    /// use inkwell::context::Context;
420    ///
421    /// let context = Context::create();
422    /// let f32_type = context.f32_type();
423    /// let struct_type = context.struct_type(&[f32_type.into(), f32_type.into()], false);
424    /// let struct_val = struct_type.const_named_struct(&[]);
425    /// let struct_array = struct_type.const_array(&[struct_val, struct_val]);
426    ///
427    /// assert!(struct_array.is_const());
428    /// ```
429    pub fn const_array(self, values: &[StructValue<'ctx>]) -> ArrayValue<'ctx> {
430        unsafe { ArrayValue::new_const_array(&self, values) }
431    }
432}
433
434unsafe impl AsTypeRef for StructType<'_> {
435    fn as_type_ref(&self) -> LLVMTypeRef {
436        self.struct_type.ty
437    }
438}
439
440impl Display for StructType<'_> {
441    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
442        write!(f, "{}", self.print_to_string())
443    }
444}
445
446/// Iterate over all `BasicTypeEnum`s in a struct.
447#[derive(Debug)]
448pub struct FieldTypesIter<'ctx> {
449    st: StructType<'ctx>,
450    i: u32,
451    count: u32,
452}
453
454impl<'ctx> Iterator for FieldTypesIter<'ctx> {
455    type Item = BasicTypeEnum<'ctx>;
456
457    fn next(&mut self) -> Option<Self::Item> {
458        if self.i < self.count {
459            let result = unsafe { self.st.get_field_type_at_index_unchecked(self.i) };
460            self.i += 1;
461            Some(result)
462        } else {
463            None
464        }
465    }
466}