1use crate::error::CoreError;
4use num_bigint::{BigInt, BigUint, Sign};
5use prost::bytes::Bytes;
6
7#[must_use]
15pub fn encode_big_int_caster(value: &BigInt) -> Bytes {
16 let (sign, magnitude) = value.to_bytes_be();
17 if magnitude.is_empty() {
18 return Bytes::from_static(&[0, 0]);
19 }
20
21 let sign_byte = match sign {
22 Sign::Minus => 1,
23 Sign::NoSign | Sign::Plus => 0,
24 };
25
26 let mut encoded = Vec::with_capacity(magnitude.len() + 1);
27 encoded.push(sign_byte);
28 encoded.extend_from_slice(&magnitude);
29 Bytes::from(encoded)
30}
31
32pub fn decode_big_int_caster(bytes: &[u8]) -> Result<Option<BigInt>, CoreError> {
39 match bytes.len() {
40 0 => Err(CoreError::InvalidBigIntEncoding(
41 "empty buffer is not a valid BigIntCaster value".to_owned(),
42 )),
43 1 => {
44 if bytes[0] == 0 {
45 Ok(None)
46 } else {
47 Err(CoreError::InvalidBigIntEncoding(format!(
48 "single-byte encoding must be nil marker 0x00, got 0x{:02x}",
49 bytes[0]
50 )))
51 }
52 }
53 _ => {
54 let magnitude = BigUint::from_bytes_be(&bytes[1..]);
55 let value = match bytes[0] {
56 0 => BigInt::from_biguint(Sign::Plus, magnitude),
57 1 => BigInt::from_biguint(Sign::Minus, magnitude),
58 sign => {
59 return Err(CoreError::InvalidBigIntEncoding(format!(
60 "invalid sign byte 0x{sign:02x}"
61 )));
62 }
63 };
64
65 Ok(Some(value))
66 }
67 }
68}
69
70pub fn parse_big_uint(value: &str) -> Result<Bytes, CoreError> {
78 let trimmed = value.trim();
79 let number = if let Some(hex_body) = trimmed.strip_prefix("0x") {
80 BigUint::parse_bytes(hex_body.as_bytes(), 16)
81 } else {
82 BigUint::parse_bytes(trimmed.as_bytes(), 10)
83 };
84 let num = number.ok_or_else(|| CoreError::InvalidNumeric(value.to_owned()))?;
85
86 Ok(encode_big_int_caster(&BigInt::from_biguint(
87 Sign::Plus,
88 num,
89 )))
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn test_encode_big_int_caster_zero() {
98 let encoded = encode_big_int_caster(&BigInt::from(0));
99 assert_eq!(encoded.as_ref(), &[0, 0]);
100 }
101
102 #[test]
103 fn test_encode_big_int_caster_positive() {
104 let encoded = encode_big_int_caster(&BigInt::from(12345));
105 assert_eq!(encoded.as_ref(), &[0, 0x30, 0x39]);
106 }
107
108 #[test]
109 fn test_encode_big_int_caster_negative() {
110 let encoded = encode_big_int_caster(&BigInt::from(-12345));
111 assert_eq!(encoded.as_ref(), &[1, 0x30, 0x39]);
112 }
113
114 #[test]
115 fn test_decode_big_int_caster_nil() {
116 assert_eq!(decode_big_int_caster(&[0]).unwrap(), None);
117 }
118
119 #[test]
120 fn test_decode_big_int_caster_zero() {
121 assert_eq!(
122 decode_big_int_caster(&[0, 0]).unwrap(),
123 Some(BigInt::from(0))
124 );
125 }
126
127 #[test]
128 fn test_decode_big_int_caster_positive() {
129 assert_eq!(
130 decode_big_int_caster(&[0, 0x30, 0x39]).unwrap(),
131 Some(BigInt::from(12345))
132 );
133 }
134
135 #[test]
136 fn test_decode_big_int_caster_negative() {
137 assert_eq!(
138 decode_big_int_caster(&[1, 0x30, 0x39]).unwrap(),
139 Some(BigInt::from(-12345))
140 );
141 }
142
143 #[test]
144 fn test_decode_big_int_caster_invalid_sign() {
145 let err = decode_big_int_caster(&[2, 3, 4]).unwrap_err();
146 assert!(matches!(err, CoreError::InvalidBigIntEncoding(_)));
147 }
148
149 #[test]
150 fn test_parse_big_uint_zero() {
151 let zero = parse_big_uint("0").unwrap();
152 assert_eq!(zero.as_ref(), &[0, 0]);
153 }
154
155 #[test]
156 fn test_parse_big_uint_decimal() {
157 let val = parse_big_uint("1000000000000000").unwrap();
158 assert!(!val.is_empty());
159 assert_eq!(val[0], 0);
160 }
161
162 #[test]
163 fn test_parse_big_uint_hex() {
164 let val = parse_big_uint("0x3039").unwrap();
165 assert_eq!(val.as_ref(), &[0, 0x30, 0x39]);
166 }
167
168 #[test]
169 fn test_parse_big_uint_invalid() {
170 let result = parse_big_uint("not_a_number");
171 assert!(result.is_err());
172 }
173
174 #[test]
175 fn test_parse_big_uint_whitespace() {
176 let val = parse_big_uint(" 123 ").unwrap();
177 assert_eq!(val.as_ref(), &[0, 123]);
178 }
179}