1use std::hash::{Hash, Hasher};
4
5use crate::{context::Context, irtype::Type, pretty::DebugWithContext, value::Value, Padding};
6use rustc_hash::FxHasher;
7use sway_types::u256::U256;
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, DebugWithContext)]
12pub struct Constant(#[in_context(values)] pub slotmap::DefaultKey);
13
14impl Constant {
15 pub fn unique(context: &mut Context, constant: ConstantContent) -> Constant {
17 let mut hasher = FxHasher::default();
18 constant.hash(&mut hasher);
19 let hash = hasher.finish();
20 context.constants_map.entry(hash).or_default();
22 let constants = context.constants_map.get(&hash).unwrap();
23 for c in constants.iter() {
25 if context.constants.get(c.0).unwrap().eq(context, &constant) {
26 return *c;
27 }
28 }
29 let constant = Constant(context.constants.insert(constant));
30 let constants = context.constants_map.get_mut(&hash).unwrap();
32 constants.push(constant);
33 constant
34 }
35
36 pub fn get_content<'a>(&self, context: &'a Context) -> &'a ConstantContent {
38 context
39 .constants
40 .get(self.0)
41 .expect("Constants are global immutable data, they must live through the context")
42 }
43}
44
45#[derive(Debug, Clone, DebugWithContext, Hash)]
47pub struct ConstantContent {
48 pub ty: Type,
49 pub value: ConstantValue,
50}
51
52pub type B256 = U256;
53
54#[derive(Debug, Clone, DebugWithContext, Hash)]
56pub enum ConstantValue {
57 Undef,
58 Unit,
59 Bool(bool),
60 Uint(u64),
61 U256(U256),
62 B256(B256),
63 String(Vec<u8>),
64 Array(Vec<ConstantContent>),
65 Slice(Vec<ConstantContent>),
66 Struct(Vec<ConstantContent>),
67 Reference(Box<ConstantContent>),
68 RawUntypedSlice(Vec<u8>),
69}
70
71type ConstantWithPadding<'a> = (&'a ConstantContent, Option<Padding>);
75
76impl ConstantContent {
77 pub fn new_unit(context: &Context) -> Self {
78 ConstantContent {
79 ty: Type::get_unit(context),
80 value: ConstantValue::Unit,
81 }
82 }
83
84 pub fn new_bool(context: &Context, b: bool) -> Self {
85 ConstantContent {
86 ty: Type::get_bool(context),
87 value: ConstantValue::Bool(b),
88 }
89 }
90
91 pub fn new_uint(context: &mut Context, nbits: u16, n: u64) -> Self {
93 ConstantContent {
94 ty: Type::new_uint(context, nbits),
95 value: match nbits {
96 256 => ConstantValue::U256(n.into()),
97 _ => ConstantValue::Uint(n),
98 },
99 }
100 }
101
102 pub fn new_uint256(context: &mut Context, n: U256) -> Self {
103 ConstantContent {
104 ty: Type::new_uint(context, 256),
105 value: ConstantValue::U256(n),
106 }
107 }
108
109 pub fn new_b256(context: &Context, bytes: [u8; 32]) -> Self {
110 ConstantContent {
111 ty: Type::get_b256(context),
112 value: ConstantValue::B256(B256::from_be_bytes(&bytes)),
113 }
114 }
115
116 pub fn new_string(context: &mut Context, string: Vec<u8>) -> Self {
117 ConstantContent {
118 ty: Type::new_string_array(context, string.len() as u64),
119 value: ConstantValue::String(string),
120 }
121 }
122
123 pub fn new_untyped_slice(context: &mut Context, bytes: Vec<u8>) -> Self {
124 ConstantContent {
125 ty: Type::new_untyped_slice(context),
126 value: ConstantValue::RawUntypedSlice(bytes),
127 }
128 }
129
130 pub fn new_array(context: &mut Context, elm_ty: Type, elems: Vec<ConstantContent>) -> Self {
131 ConstantContent {
132 ty: Type::new_array(context, elm_ty, elems.len() as u64),
133 value: ConstantValue::Array(elems),
134 }
135 }
136
137 pub fn new_struct(
138 context: &mut Context,
139 field_tys: Vec<Type>,
140 fields: Vec<ConstantContent>,
141 ) -> Self {
142 ConstantContent {
143 ty: Type::new_struct(context, field_tys),
144 value: ConstantValue::Struct(fields),
145 }
146 }
147
148 pub fn get_undef(ty: Type) -> Self {
149 ConstantContent {
150 ty,
151 value: ConstantValue::Undef,
152 }
153 }
154
155 pub fn get_unit(context: &mut Context) -> Value {
156 let new_const_contents = ConstantContent::new_unit(context);
157 let new_const = Constant::unique(context, new_const_contents);
158 Value::new_constant(context, new_const)
159 }
160
161 pub fn get_bool(context: &mut Context, value: bool) -> Value {
162 let new_const_contents = ConstantContent::new_bool(context, value);
163 let new_const = Constant::unique(context, new_const_contents);
164 Value::new_constant(context, new_const)
165 }
166
167 pub fn get_uint(context: &mut Context, nbits: u16, value: u64) -> Value {
168 let new_const_contents = ConstantContent::new_uint(context, nbits, value);
169 let new_const = Constant::unique(context, new_const_contents);
170 Value::new_constant(context, new_const)
171 }
172
173 pub fn get_uint256(context: &mut Context, value: U256) -> Value {
174 let new_const_contents = ConstantContent::new_uint256(context, value);
175 let new_const = Constant::unique(context, new_const_contents);
176 Value::new_constant(context, new_const)
177 }
178
179 pub fn get_b256(context: &mut Context, value: [u8; 32]) -> Value {
180 let new_const_contents = ConstantContent::new_b256(context, value);
181 let new_const = Constant::unique(context, new_const_contents);
182 Value::new_constant(context, new_const)
183 }
184
185 pub fn get_string(context: &mut Context, value: Vec<u8>) -> Value {
186 let new_const_contents = ConstantContent::new_string(context, value);
187 let new_const = Constant::unique(context, new_const_contents);
188 Value::new_constant(context, new_const)
189 }
190
191 pub fn get_untyped_slice(context: &mut Context, value: Vec<u8>) -> Value {
192 let new_const_contents = ConstantContent::new_untyped_slice(context, value);
193 let new_const = Constant::unique(context, new_const_contents);
194 Value::new_constant(context, new_const)
195 }
196
197 pub fn get_array(context: &mut Context, value: ConstantContent) -> Value {
199 assert!(value.ty.is_array(context));
200 let new_const = Constant::unique(context, value);
201 Value::new_constant(context, new_const)
202 }
203
204 pub fn get_struct(context: &mut Context, value: ConstantContent) -> Value {
206 assert!(value.ty.is_struct(context));
207 let new_const = Constant::unique(context, value);
208 Value::new_constant(context, new_const)
209 }
210
211 fn extract_enum_tag_and_value(
214 &self,
215 context: &Context,
216 ) -> Option<(&ConstantContent, &ConstantContent)> {
217 if !self.ty.is_enum(context) {
218 return None;
219 }
220
221 let elems = match &self.value {
222 ConstantValue::Struct(elems) if elems.len() == 2 => elems,
223 _ => return None, };
225
226 Some((&elems[0], &elems[1]))
227 }
228
229 pub fn enum_tag_and_value_with_paddings(
232 &self,
233 context: &Context,
234 ) -> Option<(ConstantWithPadding, ConstantWithPadding)> {
235 if !self.ty.is_enum(context) {
236 return None;
237 }
238
239 let tag_and_value_with_paddings = self
240 .elements_of_aggregate_with_padding(context)
241 .expect("Enums are aggregates.");
242
243 debug_assert!(tag_and_value_with_paddings.len() == 2, "In case of enums, `elements_of_aggregate_with_padding` must return exactly two elements, the tag and the value.");
244
245 let tag = tag_and_value_with_paddings[0].clone();
246 let value = tag_and_value_with_paddings[1].clone();
247
248 Some((tag, value))
249 }
250
251 pub fn array_elements_with_padding(
254 &self,
255 context: &Context,
256 ) -> Option<Vec<ConstantWithPadding>> {
257 if !self.ty.is_array(context) {
258 return None;
259 }
260
261 self.elements_of_aggregate_with_padding(context)
262 }
263
264 pub fn struct_fields_with_padding(
267 &self,
268 context: &Context,
269 ) -> Option<Vec<ConstantWithPadding>> {
270 if !self.ty.is_struct(context) {
271 return None;
272 }
273
274 self.elements_of_aggregate_with_padding(context)
275 }
276
277 fn elements_of_aggregate_with_padding(
284 &self,
285 context: &Context,
286 ) -> Option<Vec<(&ConstantContent, Option<Padding>)>> {
287 if let Some((tag, value)) = self.extract_enum_tag_and_value(context) {
289 let tag_with_padding = (tag, None);
290
291 let target_size = self.ty.get_field_types(context)[1]
296 .size(context)
297 .in_bytes_aligned() as usize;
298
299 let value_with_padding = (value, Some(Padding::Left { target_size }));
300
301 return Some(vec![tag_with_padding, value_with_padding]);
302 }
303
304 match &self.value {
305 ConstantValue::Array(elems) => Some(elems.iter().map(|el| (el, None)).collect()),
307 ConstantValue::Struct(elems) => Some(
309 elems
310 .iter()
311 .map(|el| {
312 let target_size = el.ty.size(context).in_bytes_aligned() as usize;
313 (el, Some(Padding::Right { target_size }))
314 })
315 .collect(),
316 ),
317 _ => None,
318 }
319 }
320
321 pub fn eq(&self, context: &Context, other: &Self) -> bool {
323 self.ty.eq(context, &other.ty)
324 && match (&self.value, &other.value) {
325 (ConstantValue::Undef, _) | (_, ConstantValue::Undef) => false,
327 (ConstantValue::Unit, ConstantValue::Unit) => true,
328 (ConstantValue::Bool(l0), ConstantValue::Bool(r0)) => l0 == r0,
329 (ConstantValue::Uint(l0), ConstantValue::Uint(r0)) => l0 == r0,
330 (ConstantValue::U256(l0), ConstantValue::U256(r0)) => l0 == r0,
331 (ConstantValue::B256(l0), ConstantValue::B256(r0)) => l0 == r0,
332 (ConstantValue::String(l0), ConstantValue::String(r0)) => l0 == r0,
333 (ConstantValue::Array(l0), ConstantValue::Array(r0))
334 | (ConstantValue::Struct(l0), ConstantValue::Struct(r0)) => {
335 l0.iter().zip(r0.iter()).all(|(l0, r0)| l0.eq(context, r0))
336 }
337 _ => false,
338 }
339 }
340
341 pub fn as_uint(&self) -> Option<u64> {
342 match &self.value {
343 ConstantValue::Uint(v) => Some(*v),
344 _ => None,
345 }
346 }
347
348 pub fn as_bool(&self) -> Option<bool> {
349 match &self.value {
350 ConstantValue::Bool(v) => Some(*v),
351 _ => None,
352 }
353 }
354
355 pub fn as_u256(&self) -> Option<U256> {
356 match &self.value {
357 ConstantValue::U256(v) => Some(v.clone()),
358 _ => None,
359 }
360 }
361
362 pub fn as_b256(&self) -> Option<B256> {
363 match &self.value {
364 ConstantValue::B256(v) => Some(v.clone()),
365 _ => None,
366 }
367 }
368
369 pub fn as_string(&self) -> Option<String> {
370 match &self.value {
371 ConstantValue::String(v) => Some(
372 String::from_utf8(v.clone())
373 .expect("compilation ensures that the string slice is a valid UTF-8 sequence"),
374 ),
375 _ => None,
376 }
377 }
378}