llvm_plugin_inkwell/values/
array_value.rs

1use llvm_sys::core::{LLVMIsAConstantArray, LLVMIsAConstantDataArray, LLVMIsConstantString, LLVMGetAsString};
2use llvm_sys::prelude::LLVMValueRef;
3
4use std::ffi::CStr;
5use std::fmt::{self, Display};
6
7use crate::types::ArrayType;
8use crate::values::traits::{AnyValue, AsValueRef};
9use crate::values::{InstructionValue, Value};
10
11/// An `ArrayValue` is a block of contiguous constants or variables.
12#[derive(PartialEq, Eq, Clone, Copy, Hash)]
13pub struct ArrayValue<'ctx> {
14    array_value: Value<'ctx>,
15}
16
17impl<'ctx> ArrayValue<'ctx> {
18    pub(crate) unsafe fn new(value: LLVMValueRef) -> Self {
19        assert!(!value.is_null());
20
21        ArrayValue {
22            array_value: Value::new(value),
23        }
24    }
25
26    /// Get name of the `ArrayValue`. If the value is a constant, this will
27    /// return an empty string.
28    pub fn get_name(&self) -> &CStr {
29        self.array_value.get_name()
30    }
31
32    /// Set name of the `ArrayValue`.
33    pub fn set_name(&self, name: &str) {
34        self.array_value.set_name(name)
35    }
36
37    /// Gets the type of this `ArrayValue`.
38    pub fn get_type(self) -> ArrayType<'ctx> {
39        unsafe { ArrayType::new(self.array_value.get_type()) }
40    }
41
42    /// Determines whether or not this value is null.
43    pub fn is_null(self) -> bool {
44        self.array_value.is_null()
45    }
46
47    /// Determines whether or not this value is undefined.
48    pub fn is_undef(self) -> bool {
49        self.array_value.is_undef()
50    }
51
52    /// Prints this `ArrayValue` to standard error.
53    pub fn print_to_stderr(self) {
54        self.array_value.print_to_stderr()
55    }
56
57    /// Attempt to convert this `ArrayValue` to an `InstructionValue`, if possible.
58    pub fn as_instruction(self) -> Option<InstructionValue<'ctx>> {
59        self.array_value.as_instruction()
60    }
61
62    /// Replaces all uses of this value with another value of the same type.
63    /// If used incorrectly this may result in invalid IR.
64    pub fn replace_all_uses_with(self, other: ArrayValue<'ctx>) {
65        self.array_value.replace_all_uses_with(other.as_value_ref())
66    }
67
68    /// Determines whether or not an `ArrayValue` is a constant.
69    ///
70    /// # Example
71    ///
72    /// ```no_run
73    /// use inkwell::context::Context;
74    ///
75    /// let context = Context::create();
76    /// let i64_type = context.i64_type();
77    /// let i64_val = i64_type.const_int(23, false);
78    /// let array_val = i64_type.const_array(&[i64_val]);
79    ///
80    /// assert!(array_val.is_const());
81    /// ```
82    pub fn is_const(self) -> bool {
83        self.array_value.is_const()
84    }
85
86    /// Determines whether or not an `ArrayValue` represents a constant array of `i8`s.
87    ///
88    /// # Example
89    ///
90    /// ```no_run
91    /// use inkwell::context::Context;
92    ///
93    /// let context = Context::create();
94    /// let string = context.const_string(b"my_string", false);
95    ///
96    /// assert!(string.is_const_string());
97    /// ```
98    // SubTypes: Impl only for ArrayValue<IntValue<i8>>
99    pub fn is_const_string(self) -> bool {
100        unsafe { LLVMIsConstantString(self.as_value_ref()) == 1 }
101    }
102
103    /// Obtain the string from the ArrayValue
104    /// if the value points to a constant string.
105    /// 
106    /// # Example
107    /// 
108    /// ```no_run
109    /// use inkwell::context::Context;
110    /// use std::ffi::CStr;
111    /// 
112    /// let context = Context::create();
113    /// let string = context.const_string(b"hello!", true);
114    /// 
115    /// let result = CStr::from_bytes_with_nul(b"hello!\0").unwrap();
116    /// assert_eq!(string.get_string_constant(), Some(result));
117    /// ```
118    // SubTypes: Impl only for ArrayValue<IntValue<i8>>
119    pub fn get_string_constant(&self) -> Option<&CStr> {
120        let mut len = 0;
121        let ptr = unsafe { LLVMGetAsString(self.as_value_ref(), &mut len) };
122
123        if ptr.is_null() {
124            None
125        } else {
126            unsafe { Some(CStr::from_ptr(ptr)) }
127        }
128    }
129
130    /// Determines whether or not an `ArrayValue` is a constant data array.
131    pub fn is_const_data_array(self) -> bool {
132        unsafe { !LLVMIsAConstantDataArray(self.as_value_ref()).is_null() }
133    }
134}
135
136unsafe impl AsValueRef for ArrayValue<'_> {
137    fn as_value_ref(&self) -> LLVMValueRef {
138        self.array_value.value
139    }
140}
141
142impl Display for ArrayValue<'_> {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        write!(f, "{}", self.print_to_string())
145    }
146}
147
148impl fmt::Debug for ArrayValue<'_> {
149    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
150        let llvm_value = self.print_to_string();
151        let llvm_type = self.get_type();
152        let name = self.get_name();
153        let is_const = self.is_const();
154        let is_null = self.is_null();
155        let is_const_array = unsafe { !LLVMIsAConstantArray(self.as_value_ref()).is_null() };
156        let is_const_data_array = self.is_const_data_array();
157
158        f.debug_struct("ArrayValue")
159            .field("name", &name)
160            .field("address", &self.as_value_ref())
161            .field("is_const", &is_const)
162            .field("is_const_array", &is_const_array)
163            .field("is_const_data_array", &is_const_data_array)
164            .field("is_null", &is_null)
165            .field("llvm_value", &llvm_value)
166            .field("llvm_type", &llvm_type)
167            .finish()
168    }
169}