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