dojo_types/
primitive_conversion.rs1use core::convert::TryInto;
7
8use starknet::core::types::Felt;
9
10#[derive(Debug, Copy, Clone)]
11pub struct PrimitiveFromFeltError;
12
13impl core::fmt::Display for PrimitiveFromFeltError {
14 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
15 write!(f, "Failed to convert `Felt` into primitive type")
16 }
17}
18
19impl std::error::Error for PrimitiveFromFeltError {
20 fn description(&self) -> &str {
21 "Failed to convert `Felt` into primitive type"
22 }
23}
24
25const MINUS_TWO_BYTES_REPR: [u8; 32] = [
26 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
27 255, 255, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 8,
28];
29
30pub trait FromFelt: Sized {
31 fn try_from_felt(value: Felt) -> Result<Self, PrimitiveFromFeltError>;
32}
33
34macro_rules! impl_from_felt {
35 ($into:ty) => {
36 impl FromFelt for $into {
37 fn try_from_felt(value: Felt) -> Result<Self, PrimitiveFromFeltError> {
38 let size_of_type = core::mem::size_of::<$into>();
39 let bytes_le = value.to_bytes_le();
40
41 if bytes_le[size_of_type..].iter().all(|&v| v == 0)
42 && bytes_le[size_of_type - 1] <= 0b01111111
43 {
44 Ok(<$into>::from_le_bytes(bytes_le[..size_of_type].try_into().unwrap()))
45 } else if bytes_le[size_of_type..] == MINUS_TWO_BYTES_REPR[size_of_type..]
46 && bytes_le[size_of_type - 1] >= 0b10000000
47 {
48 let offsetted_value =
49 <$into>::from_le_bytes(bytes_le[..size_of_type].try_into().unwrap());
50
51 offsetted_value.checked_sub(1).ok_or(PrimitiveFromFeltError)
52 } else if bytes_le[24..] == [17, 0, 0, 0, 0, 0, 0, 8] {
53 return Ok(-1);
54 } else {
55 Err(PrimitiveFromFeltError)
56 }
57 }
58 }
59 };
60}
61
62impl_from_felt!(i8);
63impl_from_felt!(i16);
64impl_from_felt!(i32);
65impl_from_felt!(i64);
66impl_from_felt!(i128);
67
68pub fn try_from_felt<T: FromFelt>(value: Felt) -> Result<T, PrimitiveFromFeltError> {
69 T::try_from_felt(value)
70}
71
72#[cfg(test)]
73mod tests {
74 use starknet::core::types::Felt;
75
76 use super::try_from_felt;
77
78 #[test]
79 fn test_try_from_felt() {
80 let i_8: i8 = -64;
81 let felt = Felt::from(i_8);
82 let signed_integer = try_from_felt::<i8>(felt).unwrap();
83 assert_eq!(i_8, signed_integer);
84
85 let i_16: i16 = -14293;
86 let felt = Felt::from(i_16);
87 let signed_integer = try_from_felt::<i16>(felt).unwrap();
88 assert_eq!(i_16, signed_integer);
89
90 let i_32: i32 = -194875;
91 let felt = Felt::from(i_32);
92 let signed_integer = try_from_felt::<i32>(felt).unwrap();
93 assert_eq!(i_32, signed_integer);
94
95 let i_64: i64 = -3147483648;
96 let felt = Felt::from(i_64);
97 let signed_integer = try_from_felt::<i64>(felt).unwrap();
98 assert_eq!(i_64, signed_integer);
99
100 let i_128: i128 = -170141183460469231731687303715884105728;
101 let felt = Felt::from(i_128);
102 let signed_integer = try_from_felt::<i128>(felt).unwrap();
103 assert_eq!(i_128, signed_integer);
104 }
105}