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}