neo3/neo_types/util.rs
1// #![allow(unused_imports)]
2// #![allow(dead_code)]
3// This module provides utility functions for parsing strings into numeric types, encoding numeric types to strings,
4// converting between different data representations (e.g., bytes to strings, H256 to U256), and implementing traits
5// for encoding data into Base58 and Base64 formats. These utilities are particularly useful in blockchain development,
6// where such conversions and encodings are frequently required.
7
8use primitive_types::{H160, H256, U256};
9
10use crate::{prelude::ScriptHash, TypeError};
11
12/// Parses a string into a `u64`, supporting both decimal and hexadecimal (prefixed with "0x") formats.
13///
14/// # Examples
15///
16/// ```
17/// use neo3::neo_types::parse_string_u64;
18/// let decimal = "12345";
19/// assert_eq!(parse_string_u64(decimal).unwrap(), 12345);
20///
21/// let hex = "0x3039";
22/// assert_eq!(parse_string_u64(hex).unwrap(), 12345);
23/// ```
24pub fn parse_string_u64(u64_str: &str) -> Result<u64, TypeError> {
25 if u64_str.starts_with("0x") {
26 u64::from_str_radix(&u64_str[2..], 16).map_err(|e| {
27 TypeError::InvalidFormat(format!("Failed to parse hex u64 '{}': {}", u64_str, e))
28 })
29 } else {
30 u64::from_str_radix(u64_str, 10).map_err(|e| {
31 TypeError::InvalidFormat(format!("Failed to parse decimal u64 '{}': {}", u64_str, e))
32 })
33 }
34}
35
36/// Parses a string into a `U256`, accepting both decimal and hex (prefixed with "0x") formats.
37///
38/// # Examples
39///
40/// ```
41/// use primitive_types::U256;
42/// use neo3::neo_types::parse_string_u256;
43/// let decimal = "123456789";
44/// assert_eq!(parse_string_u256(decimal).unwrap(), U256::from(123456789));
45///
46/// let hex = "0x75bcd15";
47/// assert_eq!(parse_string_u256(hex).unwrap(), U256::from(123456789));
48/// ```
49pub fn parse_string_u256(u256_str: &str) -> Result<U256, TypeError> {
50 if u256_str.starts_with("0x") {
51 U256::from_str_radix(&u256_str[2..], 16).map_err(|e| {
52 TypeError::InvalidFormat(format!("Failed to parse hex U256 '{}': {}", u256_str, e))
53 })
54 } else {
55 U256::from_str_radix(u256_str, 10).map_err(|e| {
56 TypeError::InvalidFormat(format!("Failed to parse decimal U256 '{}': {}", u256_str, e))
57 })
58 }
59}
60
61/// Converts a hexadecimal string representation of an address into a `ScriptHash`.
62///
63/// # Examples
64///
65/// ```
66/// use neo3::neo_types::{parse_address, ScriptHash};
67/// let address_hex = "0xabcdef1234567890";
68/// let script_hash = parse_address(address_hex).unwrap();
69/// // Note: This is a simplified example for demonstration
70/// ```
71pub fn parse_address(address: &str) -> Result<ScriptHash, TypeError> {
72 let bytes = hex::decode(address.trim_start_matches("0x")).map_err(|e| {
73 TypeError::InvalidFormat(format!("Failed to decode address hex '{}': {}", address, e))
74 })?;
75
76 if bytes.len() > 20 {
77 return Err(TypeError::InvalidFormat(format!(
78 "Address hex is too long: {} bytes (max 20 bytes)",
79 bytes.len()
80 )));
81 }
82
83 let mut padded_bytes = [0_u8; 20];
84 padded_bytes[20 - bytes.len()..].copy_from_slice(&bytes);
85 Ok(ScriptHash::from_slice(&padded_bytes))
86}
87
88/// Encodes an `H160` hash into a string representation.
89///
90/// # Examples
91///
92/// ```
93/// use primitive_types::H160;
94/// use neo3::neo_types::encode_string_h160;
95/// let hash = H160::repeat_byte(0xab);
96/// let encoded = encode_string_h160(&hash);
97/// assert!(encoded.starts_with("0x"));
98/// ```
99pub fn encode_string_h160(h160: &H160) -> String {
100 format!("{:?}", h160).to_owned()
101}
102
103/// Parses a hexadecimal string into an `H160` hash, padding with zeros if necessary.
104///
105/// # Examples
106///
107/// ```
108/// use primitive_types::H160;
109/// use neo3::neo_types::parse_string_h160;
110/// let hex_str = "0x123456";
111///
112/// let h160 = parse_string_h160(hex_str).unwrap();
113/// assert_eq!(h160, H160::from_low_u64_be(0x123456));
114/// ```
115pub fn parse_string_h160(h160_str: &str) -> Result<H160, TypeError> {
116 let bytes = hex::decode(h160_str.trim_start_matches("0x")).map_err(|e| {
117 TypeError::InvalidFormat(format!("Failed to decode H160 hex '{}': {}", h160_str, e))
118 })?;
119
120 if bytes.len() > 20 {
121 return Err(TypeError::InvalidFormat(format!(
122 "H160 hex is too long: {} bytes (max 20 bytes)",
123 bytes.len()
124 )));
125 }
126
127 let mut padded_bytes = [0_u8; 20];
128 padded_bytes[20 - bytes.len()..].copy_from_slice(&bytes);
129 Ok(H160::from_slice(&padded_bytes))
130}
131
132/// Parses a hexadecimal string into an `H256` hash, padding with zeros if necessary.
133///
134/// # Examples
135///
136/// ```
137/// use primitive_types::H256;
138/// use neo3::neo_types::parse_string_h256;
139/// let hex_str = "0x123456";
140/// let h256 = parse_string_h256(hex_str).unwrap();
141/// assert_eq!(h256, H256::from_low_u64_be(0x123456));
142/// ```
143pub fn parse_string_h256(h256_str: &str) -> Result<H256, TypeError> {
144 let bytes = hex::decode(h256_str.trim_start_matches("0x")).map_err(|e| {
145 TypeError::InvalidFormat(format!("Failed to decode H256 hex '{}': {}", h256_str, e))
146 })?;
147
148 if bytes.len() > 32 {
149 return Err(TypeError::InvalidFormat(format!(
150 "The provided string is too long to be a valid H256: {} (length: {})",
151 h256_str,
152 bytes.len()
153 )));
154 }
155
156 // pad the bytes to 32bytes
157 let mut padded_bytes = [0_u8; 32];
158 padded_bytes[32 - bytes.len()..].copy_from_slice(&bytes);
159
160 Ok(H256::from_slice(&padded_bytes))
161}
162
163/// Encodes an `H256` hash into a string representation.
164///
165/// # Examples
166///
167/// ```
168/// use primitive_types::H256;
169/// use neo3::neo_types::encode_string_h256;
170/// let hash = H256::repeat_byte(0xab);
171/// let encoded = encode_string_h256(&hash);
172/// assert!(encoded.starts_with("0x"));
173/// ```
174pub fn encode_string_h256(h256: &H256) -> String {
175 format!("{:?}", h256).to_owned()
176}
177
178/// Encodes a `U256` value into a hexadecimal string prefixed with "0x".
179///
180/// # Examples
181///
182/// ```
183/// use primitive_types::U256;
184/// use neo3::neo_types::encode_string_u256;
185/// let value = U256::from(255);
186/// let encoded = encode_string_u256(&value);
187/// assert_eq!(encoded, "0xff");
188/// ```
189pub fn encode_string_u256(u256: &U256) -> String {
190 format!("0x{:x}", u256).to_owned()
191}
192
193/// Encodes a vector of `U256` values into a vector of hexadecimal strings.
194///
195/// # Examples
196///
197/// ```
198/// use primitive_types::U256;
199/// use neo3::neo_types::encode_vec_string_vec_u256;
200/// let values = vec![U256::from(1), U256::from(2)];
201/// let encoded_values = encode_vec_string_vec_u256(values);
202/// assert_eq!(encoded_values, vec!["0x1", "0x2"]);
203/// ```
204pub fn encode_vec_string_vec_u256(item: Vec<U256>) -> Vec<String> {
205 item.iter().map(|x| encode_string_u256(&x)).collect()
206}
207
208/// Parses a vector of hexadecimal string representations into a vector of `U256` values.
209///
210/// # Examples
211///
212/// ```
213/// use primitive_types::U256;
214/// use neo3::neo_types::parse_vec_string_vec_u256;
215/// let strings = vec!["0x1".to_string(), "0x2".to_string()];
216/// let u256_values = parse_vec_string_vec_u256(strings).unwrap();
217/// assert_eq!(u256_values, vec![U256::from(1), U256::from(2)]);
218/// ```
219pub fn parse_vec_string_vec_u256(item: Vec<String>) -> Result<Vec<U256>, TypeError> {
220 let mut result = Vec::with_capacity(item.len());
221
222 for x in item {
223 result.push(parse_string_u256(&x)?);
224 }
225
226 Ok(result)
227}
228
229/// Converts an `H256` hash into a `U256` value.
230///
231/// # Examples
232///
233/// ```
234/// use primitive_types::{H256, U256};
235/// use neo3::neo_types::h256_to_u256;
236/// let h256 = H256::repeat_byte(0x01);
237/// let u256 = h256_to_u256(h256);
238/// assert_eq!(u256, U256::from_big_endian(&[0x01; 32]));
239/// ```
240pub fn h256_to_u256(item: H256) -> U256 {
241 U256::from_big_endian(item.as_bytes())
242}
243
244/// Converts a byte slice into a hexadecimal string prefixed with "0x".
245///
246/// # Examples
247///
248/// ```
249/// use neo3::neo_types::bytes_to_string;
250/// let bytes = [0xde, 0xad, 0xbe, 0xef];
251/// let hex_string = bytes_to_string(&bytes);
252/// assert_eq!(hex_string, "0xdeadbeef");
253/// ```
254pub fn bytes_to_string(mybytes: &[u8]) -> String {
255 format!("0x{}", hex::encode(mybytes))
256}
257
258/// Attempts to convert a hexadecimal string (optionally prefixed with "0x") into a byte vector.
259///
260/// # Examples
261///
262/// ```
263/// use neo3::neo_types::string_to_bytes;
264/// let hex_string = "0xdeadbeef";
265/// let bytes = string_to_bytes(hex_string).unwrap();
266/// assert_eq!(bytes, vec![0xde, 0xad, 0xbe, 0xef]);
267///
268/// let invalid_hex = "deadbeefg";
269/// assert!(string_to_bytes(invalid_hex).is_err());
270/// ```
271pub fn string_to_bytes(mystring: &str) -> Result<Vec<u8>, TypeError> {
272 if mystring.starts_with("0x") {
273 let mystring = mystring.trim_start_matches("0x");
274 hex::decode(mystring).map_err(|e| {
275 TypeError::InvalidFormat(format!("Failed to decode hex string '{}': {}", mystring, e))
276 })
277 } else {
278 Err(TypeError::InvalidFormat(format!(
279 "String '{}' does not start with '0x' prefix",
280 mystring
281 )))
282 }
283}
284
285/// Calculates the square root of a `U256` value, returning another `U256`.
286///
287/// # Examples
288///
289/// ```
290/// use primitive_types::U256;
291/// use neo3::neo_types::u256_sqrt;
292/// let input = U256::from(16);
293/// let sqrt = u256_sqrt(&input);
294/// assert_eq!(sqrt, U256::from(4));
295/// ```
296pub fn u256_sqrt(input: &U256) -> U256 {
297 if *input < 2.into() {
298 return input.clone();
299 }
300 let mut x: U256 = (input + U256::one()) >> 1;
301 let mut y = input.clone();
302 while x < y {
303 y = x;
304 x = (input / x + x) >> 1;
305 }
306 y
307}
308
309/// Returns the minimum of two `U256` values.
310///
311/// # Examples
312///
313/// ```
314/// use primitive_types::U256;
315/// use neo3::neo_types::u256_min;
316/// let a = U256::from(1);
317/// let b = U256::from(2);
318/// assert_eq!(u256_min(a, b), U256::from(1));
319/// ```
320pub fn u256_min(x: U256, y: U256) -> U256 {
321 if x > y {
322 y
323 } else {
324 x
325 }
326}
327
328/// Converts a vector of bytes into an array of 32 bytes. Returns an error if the vector is not exactly 32 bytes long.
329///
330/// # Examples
331///
332/// ```
333/// use neo3::neo_types::vec_to_array32;
334/// let vec = vec![0_u8; 32];
335/// let array = vec_to_array32(vec).unwrap();
336/// assert_eq!(array.len(), 32);
337/// ```
338pub fn vec_to_array32(vec: Vec<u8>) -> Result<[u8; 32], TypeError> {
339 if vec.len() != 32 {
340 return Err(TypeError::InvalidData(
341 "Vector does not contain exactly 32 elements".to_string(),
342 ));
343 }
344
345 let mut array = [0u8; 32];
346 let bytes = &vec[..array.len()]; // Take a slice of the vec
347 array.copy_from_slice(bytes); // Copy the slice into the array
348 Ok(array)
349}
350
351/// Calculates the size of a variable as the number of bytes required to represent it.
352///
353/// # Examples
354///
355/// ```
356/// use neo3::neo_types::var_size;
357/// assert_eq!(var_size(256), 2); // 256 requires at least 2 bytes.
358/// assert_eq!(var_size(1), 1); // Smallest non-zero values require at least 1 byte.
359/// ```
360pub fn var_size(value: usize) -> usize {
361 let mut v = value;
362 let mut bytes = 0;
363 while v > 0 {
364 v >>= 8;
365 bytes += 1;
366 }
367 if bytes == 0 {
368 1
369 } else {
370 bytes
371 }
372}
373
374pub trait ToBase58 {
375 /// Encodes a byte slice into a Base58 string.
376 ///
377 /// # Examples
378 ///
379 /// ```
380 /// use neo3::neo_types::ToBase58;
381 /// let bytes = [1, 2, 3];
382 /// assert_eq!(bytes.to_base58(), "Ldp");
383 /// ```
384 fn to_base58(&self) -> String;
385}
386
387impl ToBase58 for [u8] {
388 fn to_base58(&self) -> String {
389 bs58::encode(self).into_string()
390 }
391}
392
393pub trait ToBase64 {
394 /// Encodes a byte slice into a Base64 string.
395 ///
396 /// # Examples
397 ///
398 /// ```
399 /// use neo3::neo_types::ToBase64;
400 /// let bytes = [1, 2, 3];
401 /// assert_eq!(bytes.to_base64(), "AQID");
402 /// ```
403 fn to_base64(&self) -> String;
404}
405
406impl ToBase64 for [u8] {
407 fn to_base64(&self) -> String {
408 base64::encode(self)
409 }
410}
411
412#[cfg(test)]
413mod test {
414 use super::*;
415
416 // #[test]
417 // pub fn test_blake2var_hash() {
418 // let mut data = [0_u8; 24];
419 // data[0..4].copy_from_slice(b"evm:");
420 // data[4..24].copy_from_slice(&hex::decode("7EF99B0E5bEb8ae42DbF126B40b87410a440a32a").unwrap());
421 // let hash = blake2_hash(&data);
422 // let actual = hex::decode("65f5fbd10250447019bb8b9e06f6918d033b2feb6478470137b1a552656e2911").unwrap();
423 // assert_eq!(&hash, actual.as_slice());
424 // }
425
426 #[test]
427 pub fn test_bytes_to_string() {
428 let mybytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
429 let bytestring = bytes_to_string(&mybytes);
430 let orig_bytestring = "0x0102030405060708090a";
431 assert_eq!(&bytestring, orig_bytestring);
432
433 // Test error case - string without 0x prefix
434 let error_bytestring = "0102030405060708090a";
435 let error_result = string_to_bytes(error_bytestring);
436 assert!(error_result.is_err());
437
438 // Test success case
439 let ok_mybytes = string_to_bytes(orig_bytestring).expect("Should decode valid hex string");
440 assert_eq!(&mybytes[..], &ok_mybytes[..]);
441 }
442}