inkwell/values/
array_value.rs

1#[llvm_versions(..17)]
2use llvm_sys::core::LLVMConstArray;
3#[llvm_versions(17..)]
4use llvm_sys::core::LLVMConstArray2 as LLVMConstArray;
5use llvm_sys::core::{LLVMGetAsString, LLVMIsAConstantArray, LLVMIsAConstantDataArray, LLVMIsConstantString};
6use llvm_sys::prelude::LLVMTypeRef;
7use llvm_sys::prelude::LLVMValueRef;
8
9use std::ffi::CStr;
10use std::fmt::{self, Display};
11
12use crate::types::{ArrayType, AsTypeRef};
13use crate::values::traits::{AnyValue, AsValueRef};
14use crate::values::{InstructionValue, Value};
15
16/// An `ArrayValue` is a block of contiguous constants or variables.
17#[derive(PartialEq, Eq, Clone, Copy, Hash)]
18pub struct ArrayValue<'ctx> {
19    array_value: Value<'ctx>,
20}
21
22impl<'ctx> ArrayValue<'ctx> {
23    /// Get a value from an [LLVMValueRef].
24    ///
25    /// # Safety
26    ///
27    /// The ref must be valid and of type array.
28    pub unsafe fn new(value: LLVMValueRef) -> Self {
29        assert!(!value.is_null());
30
31        ArrayValue {
32            array_value: Value::new(value),
33        }
34    }
35
36    /// Creates a new constant `ArrayValue` with the given type and values.
37    ///
38    /// # Safety
39    ///
40    /// `values` must be of the same type as `ty`.
41    pub unsafe fn new_const_array<T: AsTypeRef, V: AsValueRef>(ty: &T, values: &[V]) -> Self {
42        let values = values.iter().map(V::as_value_ref).collect::<Vec<_>>();
43        Self::new_raw_const_array(ty.as_type_ref(), &values)
44    }
45
46    /// Creates a new constant `ArrayValue` with the given type and values.
47    ///
48    /// # Safety
49    ///
50    /// `values` must be of the same type as `ty`.
51    pub unsafe fn new_raw_const_array(ty: LLVMTypeRef, values: &[LLVMValueRef]) -> Self {
52        unsafe { Self::new(LLVMConstArray(ty, values.as_ptr().cast_mut(), values.len() as _)) }
53    }
54
55    /// Get name of the `ArrayValue`. If the value is a constant, this will
56    /// return an empty string.
57    pub fn get_name(&self) -> &CStr {
58        self.array_value.get_name()
59    }
60
61    /// Set name of the `ArrayValue`.
62    pub fn set_name(&self, name: &str) {
63        self.array_value.set_name(name)
64    }
65
66    /// Gets the type of this `ArrayValue`.
67    pub fn get_type(self) -> ArrayType<'ctx> {
68        unsafe { ArrayType::new(self.array_value.get_type()) }
69    }
70
71    /// Determines whether or not this value is null.
72    pub fn is_null(self) -> bool {
73        self.array_value.is_null()
74    }
75
76    /// Determines whether or not this value is undefined.
77    pub fn is_undef(self) -> bool {
78        self.array_value.is_undef()
79    }
80
81    /// Prints this `ArrayValue` to standard error.
82    pub fn print_to_stderr(self) {
83        self.array_value.print_to_stderr()
84    }
85
86    /// Attempt to convert this `ArrayValue` to an `InstructionValue`, if possible.
87    pub fn as_instruction(self) -> Option<InstructionValue<'ctx>> {
88        self.array_value.as_instruction()
89    }
90
91    /// Replaces all uses of this value with another value of the same type.
92    /// If used incorrectly this may result in invalid IR.
93    pub fn replace_all_uses_with(self, other: ArrayValue<'ctx>) {
94        self.array_value.replace_all_uses_with(other.as_value_ref())
95    }
96
97    /// Determines whether or not an `ArrayValue` is a constant.
98    ///
99    /// # Example
100    ///
101    /// ```no_run
102    /// use inkwell::context::Context;
103    ///
104    /// let context = Context::create();
105    /// let i64_type = context.i64_type();
106    /// let i64_val = i64_type.const_int(23, false);
107    /// let array_val = i64_type.const_array(&[i64_val]);
108    ///
109    /// assert!(array_val.is_const());
110    /// ```
111    pub fn is_const(self) -> bool {
112        self.array_value.is_const()
113    }
114
115    /// Determines whether or not an `ArrayValue` represents a constant array of `i8`s.
116    ///
117    /// # Example
118    ///
119    /// ```no_run
120    /// use inkwell::context::Context;
121    ///
122    /// let context = Context::create();
123    /// let string = context.const_string(b"my_string", false);
124    ///
125    /// assert!(string.is_const_string());
126    /// ```
127    // SubTypes: Impl only for ArrayValue<IntValue<i8>>
128    pub fn is_const_string(self) -> bool {
129        unsafe { LLVMIsConstantString(self.as_value_ref()) == 1 }
130    }
131
132    /// Obtain the string from the ArrayValue
133    /// if the value points to a constant string.
134    ///
135    /// # Example
136    ///
137    /// ```no_run
138    /// use inkwell::context::Context;
139    /// use std::ffi::CStr;
140    ///
141    /// let context = Context::create();
142    /// let string = context.const_string(b"hello!", false);
143    ///
144    /// let result = b"hello!".as_slice();
145    /// assert_eq!(string.as_const_string(), Some(result));
146    /// ```
147    // SubTypes: Impl only for ArrayValue<IntValue<i8>>
148    pub fn as_const_string(&self) -> Option<&[u8]> {
149        let mut len = 0;
150        let ptr = unsafe { LLVMGetAsString(self.as_value_ref(), &mut len) };
151
152        if ptr.is_null() {
153            None
154        } else {
155            unsafe { Some(std::slice::from_raw_parts(ptr.cast(), len)) }
156        }
157    }
158
159    /// Obtain the string from the ArrayValue
160    /// if the value points to a constant string.
161    ///
162    /// # Example
163    ///
164    /// ```no_run
165    /// use inkwell::context::Context;
166    /// use std::ffi::CStr;
167    ///
168    /// let context = Context::create();
169    /// let string = context.const_string(b"hello!", true);
170    ///
171    /// let result = CStr::from_bytes_with_nul(b"hello!\0").unwrap();
172    /// assert_eq!(string.get_string_constant(), Some(result));
173    /// ```
174    // SubTypes: Impl only for ArrayValue<IntValue<i8>>
175    #[deprecated = "llvm strings can contain internal NULs, and this function truncates such values, use as_const_string instead"]
176    pub fn get_string_constant(&self) -> Option<&CStr> {
177        let mut len = 0;
178        let ptr = unsafe { LLVMGetAsString(self.as_value_ref(), &mut len) };
179
180        if ptr.is_null() {
181            None
182        } else {
183            unsafe { Some(CStr::from_ptr(ptr)) }
184        }
185    }
186}
187
188unsafe impl AsValueRef for ArrayValue<'_> {
189    fn as_value_ref(&self) -> LLVMValueRef {
190        self.array_value.value
191    }
192}
193
194impl Display for ArrayValue<'_> {
195    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196        write!(f, "{}", self.print_to_string())
197    }
198}
199
200impl fmt::Debug for ArrayValue<'_> {
201    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
202        let llvm_value = self.print_to_string();
203        let llvm_type = self.get_type();
204        let name = self.get_name();
205        let is_const = self.is_const();
206        let is_null = self.is_null();
207        let is_const_array = unsafe { !LLVMIsAConstantArray(self.as_value_ref()).is_null() };
208        let is_const_data_array = unsafe { !LLVMIsAConstantDataArray(self.as_value_ref()).is_null() };
209
210        f.debug_struct("ArrayValue")
211            .field("name", &name)
212            .field("address", &self.as_value_ref())
213            .field("is_const", &is_const)
214            .field("is_const_array", &is_const_array)
215            .field("is_const_data_array", &is_const_data_array)
216            .field("is_null", &is_null)
217            .field("llvm_value", &llvm_value)
218            .field("llvm_type", &llvm_type)
219            .finish()
220    }
221}