inkwell/values/
struct_value.rs

1use llvm_sys::core::{LLVMGetNumOperands, LLVMGetOperand, LLVMSetOperand};
2
3use llvm_sys::prelude::LLVMValueRef;
4
5use std::ffi::CStr;
6use std::fmt::{self, Display};
7
8use crate::types::StructType;
9use crate::values::traits::AsValueRef;
10use crate::values::{BasicValue, InstructionValue, Value};
11
12use super::{AnyValue, BasicValueEnum};
13
14#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
15pub struct StructValue<'ctx> {
16    struct_value: Value<'ctx>,
17}
18
19impl<'ctx> StructValue<'ctx> {
20    /// Get a value from an [LLVMValueRef].
21    ///
22    /// # Safety
23    ///
24    /// The ref must be valid and of type struct.
25    pub unsafe fn new(value: LLVMValueRef) -> Self {
26        assert!(!value.is_null());
27
28        StructValue {
29            struct_value: Value::new(value),
30        }
31    }
32
33    /// Gets the value of a field belonging to this `StructValue`.
34    ///
35    /// ```no_run
36    /// use inkwell::context::Context;
37    ///
38    /// let context = Context::create();
39    /// let i32_type = context.i32_type();
40    /// let i8_type = context.i8_type();
41    /// let i8_val = i8_type.const_all_ones();
42    /// let i32_val = i32_type.const_all_ones();
43    /// let struct_type = context.struct_type(&[i8_type.into(), i32_type.into()], false);
44    /// let struct_val = struct_type.const_named_struct(&[i8_val.into(), i32_val.into()]);
45    ///
46    /// assert!(struct_val.get_field_at_index(0).is_some());
47    /// assert!(struct_val.get_field_at_index(1).is_some());
48    /// assert!(struct_val.get_field_at_index(3).is_none());
49    /// assert!(struct_val.get_field_at_index(0).unwrap().is_int_value());
50    /// ```
51    pub fn get_field_at_index(self, index: u32) -> Option<BasicValueEnum<'ctx>> {
52        // OoB indexing seems to be unchecked and therefore is UB
53        if index >= self.count_fields() {
54            return None;
55        }
56
57        Some(unsafe { self.get_field_at_index_unchecked(index) })
58    }
59
60    /// Gets the value of a field belonging to this `StructValue`.
61    ///
62    /// # Safety
63    ///
64    /// The index must be smaller than [StructValue::count_fields].
65    pub unsafe fn get_field_at_index_unchecked(self, index: u32) -> BasicValueEnum<'ctx> {
66        unsafe { BasicValueEnum::new(LLVMGetOperand(self.as_value_ref(), index)) }
67    }
68
69    /// Get a field value iterator.
70    pub fn get_fields(self) -> FieldValueIter<'ctx> {
71        FieldValueIter {
72            sv: self,
73            i: 0,
74            count: self.count_fields(),
75        }
76    }
77
78    /// Sets the value of a field belonging to this `StructValue`.
79    pub fn set_field_at_index<BV: BasicValue<'ctx>>(self, index: u32, val: BV) -> bool {
80        if self
81            .get_type()
82            .get_field_type_at_index(index)
83            .map(|t| t == val.as_basic_value_enum().get_type())
84            != Some(true)
85        {
86            return false;
87        }
88
89        unsafe { LLVMSetOperand(self.as_value_ref(), index, val.as_value_ref()) }
90
91        true
92    }
93
94    /// Counts the number of fields.
95    ///
96    /// ```no_run
97    /// use inkwell::context::Context;
98    ///
99    /// let context = Context::create();
100    /// let i32_type = context.i32_type();
101    /// let i8_type = context.i8_type();
102    /// let i8_val = i8_type.const_all_ones();
103    /// let i32_val = i32_type.const_all_ones();
104    /// let struct_type = context.struct_type(&[i8_type.into(), i32_type.into()], false);
105    /// let struct_val = struct_type.const_named_struct(&[i8_val.into(), i32_val.into()]);
106    ///
107    /// assert_eq!(struct_val.count_fields(), 2);
108    /// assert_eq!(struct_val.count_fields(), struct_type.count_fields());
109    /// ```
110    pub fn count_fields(self) -> u32 {
111        unsafe { LLVMGetNumOperands(self.as_value_ref()) as u32 }
112    }
113
114    /// Gets the name of a `StructValue`. If the value is a constant, this will
115    /// return an empty string.
116    pub fn get_name(&self) -> &CStr {
117        self.struct_value.get_name()
118    }
119
120    /// Get name of the `StructValue`.
121    pub fn set_name(&self, name: &str) {
122        self.struct_value.set_name(name)
123    }
124
125    pub fn get_type(self) -> StructType<'ctx> {
126        unsafe { StructType::new(self.struct_value.get_type()) }
127    }
128
129    pub fn is_null(self) -> bool {
130        self.struct_value.is_null()
131    }
132
133    pub fn is_undef(self) -> bool {
134        self.struct_value.is_undef()
135    }
136
137    pub fn print_to_stderr(self) {
138        self.struct_value.print_to_stderr()
139    }
140
141    pub fn as_instruction(self) -> Option<InstructionValue<'ctx>> {
142        self.struct_value.as_instruction()
143    }
144
145    pub fn replace_all_uses_with(self, other: StructValue<'ctx>) {
146        self.struct_value.replace_all_uses_with(other.as_value_ref())
147    }
148
149    /// Determines whether or not a `StructValue` is a constant.
150    ///
151    /// # Example
152    ///
153    /// ```no_run
154    /// use inkwell::{context::Context, values::BasicValue};
155    ///
156    /// let context = Context::create();
157    /// let i64_type = context.i64_type();
158    /// let i64_val = i64_type.const_int(23, false).as_basic_value_enum();
159    /// let struct_val = context.const_struct(&[i64_val, i64_val], false);
160    ///
161    /// assert!(struct_val.is_const());
162    /// ```
163    pub fn is_const(self) -> bool {
164        self.struct_value.is_const()
165    }
166}
167
168unsafe impl AsValueRef for StructValue<'_> {
169    fn as_value_ref(&self) -> LLVMValueRef {
170        self.struct_value.value
171    }
172}
173
174impl Display for StructValue<'_> {
175    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176        write!(f, "{}", self.print_to_string())
177    }
178}
179
180/// Iterate over all the field values of this struct.
181#[derive(Debug)]
182pub struct FieldValueIter<'ctx> {
183    sv: StructValue<'ctx>,
184    i: u32,
185    count: u32,
186}
187
188impl<'ctx> Iterator for FieldValueIter<'ctx> {
189    type Item = BasicValueEnum<'ctx>;
190
191    fn next(&mut self) -> Option<Self::Item> {
192        if self.i < self.count {
193            let result = unsafe { self.sv.get_field_at_index_unchecked(self.i) };
194            self.i += 1;
195            Some(result)
196        } else {
197            None
198        }
199    }
200}