huff_neo_utils/
push_value.rs1use crate::bytes_util::literal_gen;
6use crate::evm_version::EVMVersion;
7use alloy_primitives::{B256, hex};
8
9#[derive(Debug, Clone, PartialEq)]
15pub struct PushValue {
16 pub value: B256,
18}
19
20impl PushValue {
21 pub fn new(value: B256) -> PushValue {
23 PushValue { value }
24 }
25
26 pub fn to_hex_with_opcode(&self, evm_version: &EVMVersion) -> String {
41 literal_gen(evm_version, &self.value.0)
42 }
43
44 pub fn to_hex_trimmed(&self) -> String {
54 let first_non_zero = self.value.0.iter().position(|&b| b != 0).unwrap_or(32);
56 let trimmed_bytes = &self.value.0[first_non_zero..];
57 hex::encode(trimmed_bytes)
58 }
59
60 pub fn to_hex_full(&self) -> String {
70 hex::encode(self.value.0)
71 }
72
73 pub fn to_hex_full_with_opcode(&self) -> String {
84 format!("7f{}", self.to_hex_full())
85 }
86}
87
88impl From<[u8; 32]> for PushValue {
90 fn from(bytes: [u8; 32]) -> Self {
91 PushValue { value: B256::from(bytes) }
92 }
93}
94
95impl From<&[u8; 32]> for PushValue {
97 fn from(bytes: &[u8; 32]) -> Self {
98 PushValue { value: B256::from(*bytes) }
99 }
100}
101
102impl From<B256> for PushValue {
104 fn from(value: B256) -> Self {
105 PushValue { value }
106 }
107}
108
109impl From<[u8; 4]> for PushValue {
113 fn from(bytes: [u8; 4]) -> Self {
114 let mut padded = [0u8; 32];
115 padded[28..32].copy_from_slice(&bytes);
116 PushValue { value: B256::from(padded) }
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use crate::evm_version::SupportedEVMVersions;
124 use alloy_primitives::B256;
125
126 #[test]
127 fn test_to_hex_trimmed_single_byte() {
128 let mut bytes = [0u8; 32];
129 bytes[31] = 0x01;
130 let pv = PushValue::from(bytes);
131 assert_eq!(pv.to_hex_trimmed(), "01");
132 }
133
134 #[test]
135 fn test_to_hex_trimmed_multiple_bytes() {
136 let mut bytes = [0u8; 32];
137 bytes[30] = 0x12;
138 bytes[31] = 0x34;
139 let pv = PushValue::from(bytes);
140 assert_eq!(pv.to_hex_trimmed(), "1234");
141 }
142
143 #[test]
144 fn test_to_hex_trimmed_all_zeros() {
145 let bytes = [0u8; 32];
146 let pv = PushValue::from(bytes);
147 assert_eq!(pv.to_hex_trimmed(), "");
148 }
149
150 #[test]
151 fn test_to_hex_trimmed_full_32_bytes() {
152 let bytes = [0xff; 32];
153 let pv = PushValue::from(bytes);
154 assert_eq!(pv.to_hex_trimmed(), "f".repeat(64));
155 }
156
157 #[test]
158 fn test_to_hex_trimmed_leading_zeros() {
159 let mut bytes = [0u8; 32];
160 bytes[28] = 0xde;
161 bytes[29] = 0xad;
162 bytes[30] = 0xbe;
163 bytes[31] = 0xef;
164 let pv = PushValue::from(bytes);
165 assert_eq!(pv.to_hex_trimmed(), "deadbeef");
166 }
167
168 #[test]
169 fn test_to_hex_full_single_byte() {
170 let mut bytes = [0u8; 32];
171 bytes[31] = 0x01;
172 let pv = PushValue::from(bytes);
173 assert_eq!(pv.to_hex_full(), "0000000000000000000000000000000000000000000000000000000000000001");
174 }
175
176 #[test]
177 fn test_to_hex_full_multiple_bytes() {
178 let mut bytes = [0u8; 32];
179 bytes[30] = 0x12;
180 bytes[31] = 0x34;
181 let pv = PushValue::from(bytes);
182 assert_eq!(pv.to_hex_full(), "0000000000000000000000000000000000000000000000000000000000001234");
183 }
184
185 #[test]
186 fn test_to_hex_full_all_zeros() {
187 let bytes = [0u8; 32];
188 let pv = PushValue::from(bytes);
189 assert_eq!(pv.to_hex_full(), "0".repeat(64));
190 }
191
192 #[test]
193 fn test_to_hex_full_all_ones() {
194 let bytes = [0xff; 32];
195 let pv = PushValue::from(bytes);
196 assert_eq!(pv.to_hex_full(), "f".repeat(64));
197 }
198
199 #[test]
200 fn test_to_hex_full_preserves_leading_zeros() {
201 let mut bytes = [0u8; 32];
202 bytes[28] = 0xde;
203 bytes[29] = 0xad;
204 bytes[30] = 0xbe;
205 bytes[31] = 0xef;
206 let pv = PushValue::from(bytes);
207 assert_eq!(pv.to_hex_full(), "00000000000000000000000000000000000000000000000000000000deadbeef");
208 }
209
210 #[test]
211 fn test_to_hex_with_opcode_push1() {
212 let mut bytes = [0u8; 32];
213 bytes[31] = 0x42;
214 let pv = PushValue::from(bytes);
215 let evm = EVMVersion::default();
216 assert_eq!(pv.to_hex_with_opcode(&evm), "6042");
218 }
219
220 #[test]
221 fn test_to_hex_with_opcode_push2() {
222 let mut bytes = [0u8; 32];
223 bytes[30] = 0x12;
224 bytes[31] = 0x34;
225 let pv = PushValue::from(bytes);
226 let evm = EVMVersion::default();
227 assert_eq!(pv.to_hex_with_opcode(&evm), "611234");
229 }
230
231 #[test]
232 fn test_to_hex_with_opcode_push0_shanghai() {
233 let pv = PushValue::from(B256::ZERO);
234 let evm = EVMVersion::new(SupportedEVMVersions::Shanghai);
235 assert_eq!(pv.to_hex_with_opcode(&evm), "5f");
237 }
238
239 #[test]
240 fn test_to_hex_with_opcode_push1_zero_pre_shanghai() {
241 let pv = PushValue::from(B256::ZERO);
242 let evm = EVMVersion::new(SupportedEVMVersions::Paris);
243 assert_eq!(pv.to_hex_with_opcode(&evm), "6000");
245 }
246
247 #[test]
248 fn test_to_hex_with_opcode_push4() {
249 let mut bytes = [0u8; 32];
250 bytes[28] = 0xde;
251 bytes[29] = 0xad;
252 bytes[30] = 0xbe;
253 bytes[31] = 0xef;
254 let pv = PushValue::from(bytes);
255 let evm = EVMVersion::default();
256 assert_eq!(pv.to_hex_with_opcode(&evm), "63deadbeef");
258 }
259
260 #[test]
261 fn test_to_hex_with_opcode_push32() {
262 let pv = PushValue::from(B256::repeat_byte(0xff));
263 let evm = EVMVersion::default();
264 assert_eq!(pv.to_hex_with_opcode(&evm), format!("7f{}", "f".repeat(64)));
266 }
267
268 #[test]
269 fn test_from_u8_array_32() {
270 let mut bytes = [0u8; 32];
271 bytes[31] = 0x42;
272 let pv = PushValue::from(bytes);
273 assert_eq!(pv.value, B256::from(bytes));
274 }
275
276 #[test]
277 fn test_from_ref_u8_array_32() {
278 let mut bytes = [0u8; 32];
279 bytes[31] = 0x42;
280 let pv = PushValue::from(&bytes);
281 assert_eq!(pv.value, B256::from(bytes));
282 }
283
284 #[test]
285 fn test_from_b256() {
286 let b256 = B256::repeat_byte(0xaa);
287 let pv = PushValue::from(b256);
288 assert_eq!(pv.value, b256);
289 }
290
291 #[test]
292 fn test_from_u8_array_4_selector() {
293 let selector = [0xde, 0xad, 0xbe, 0xef];
294 let pv = PushValue::from(selector);
295
296 let mut expected = [0u8; 32];
298 expected[28..32].copy_from_slice(&selector);
299 assert_eq!(pv.value, B256::from(expected));
300 assert_eq!(pv.to_hex_trimmed(), "deadbeef");
301 }
302
303 #[test]
304 fn test_into_conversion() {
305 let mut bytes = [0u8; 32];
306 bytes[31] = 0xff;
307 let pv: PushValue = bytes.into();
308 assert_eq!(pv.value, B256::from(bytes));
309 }
310
311 #[test]
312 fn test_from_b256_zero() {
313 let pv = PushValue::from(B256::ZERO);
314 assert_eq!(pv.value, B256::ZERO);
315 assert_eq!(pv.to_hex_trimmed(), "");
316 }
317}