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}