fuel_types/
numeric_types.rs1use core::{
2 array::TryFromSliceError,
3 borrow::{
4 Borrow,
5 BorrowMut,
6 },
7 convert::TryFrom,
8 fmt,
9 ops::{
10 Deref,
11 DerefMut,
12 },
13 str,
14};
15
16#[cfg(feature = "random")]
17use rand::{
18 distributions::{
19 Distribution,
20 Standard,
21 },
22 Rng,
23};
24
25#[cfg(all(feature = "alloc", feature = "typescript"))]
26use alloc::vec::Vec;
27
28macro_rules! key {
29 ($i:ident, $t:ty) => {
30 #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
31 #[repr(transparent)]
33 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34 #[cfg_attr(feature = "serde", serde(transparent))]
35 #[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
36 #[derive(
37 fuel_types::canonical::Serialize, fuel_types::canonical::Deserialize,
38 )]
39 pub struct $i($t);
40
41 key_methods!($i, $t);
42
43 #[cfg(feature = "random")]
44 impl Distribution<$i> for Standard {
45 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $i {
46 $i(rng.gen())
47 }
48 }
49 };
50}
51
52macro_rules! key_methods {
53 ($i:ident, $t:ty) => {
54 const _: () = {
55 const SIZE: usize = core::mem::size_of::<$t>();
56
57 impl $i {
58 pub const fn new(number: $t) -> Self {
60 Self(number)
61 }
62
63 pub fn to_bytes(self) -> [u8; SIZE] {
65 self.0.to_be_bytes()
66 }
67 }
68
69 #[cfg(feature = "typescript")]
70 #[wasm_bindgen::prelude::wasm_bindgen]
71 impl $i {
72 #[wasm_bindgen::prelude::wasm_bindgen(constructor)]
73 pub fn from_number(number: $t) -> Self {
75 Self(number)
76 }
77
78 #[wasm_bindgen(js_name = to_bytes)]
80 pub fn to_bytes_typescript(self) -> Vec<u8> {
81 self.to_bytes().to_vec()
82 }
83
84 #[wasm_bindgen(js_name = as_usize)]
86 pub fn as_usize_typescript(&self) -> usize {
87 usize::try_from(self.0).expect("Cannot convert to usize")
88 }
89 }
90
91 #[cfg(feature = "random")]
92 impl rand::Fill for $i {
93 fn try_fill<R: rand::Rng + ?Sized>(
94 &mut self,
95 rng: &mut R,
96 ) -> Result<(), rand::Error> {
97 let number = rng.gen();
98 *self = $i(number);
99
100 Ok(())
101 }
102 }
103
104 impl Deref for $i {
105 type Target = $t;
106
107 fn deref(&self) -> &$t {
108 &self.0
109 }
110 }
111
112 impl Borrow<$t> for $i {
113 fn borrow(&self) -> &$t {
114 &self.0
115 }
116 }
117
118 impl BorrowMut<$t> for $i {
119 fn borrow_mut(&mut self) -> &mut $t {
120 &mut self.0
121 }
122 }
123
124 impl DerefMut for $i {
125 fn deref_mut(&mut self) -> &mut $t {
126 &mut self.0
127 }
128 }
129
130 impl From<[u8; SIZE]> for $i {
131 fn from(bytes: [u8; SIZE]) -> Self {
132 Self(<$t>::from_be_bytes(bytes))
133 }
134 }
135
136 impl From<$t> for $i {
137 fn from(value: $t) -> Self {
138 Self(value)
139 }
140 }
141
142 impl From<$i> for [u8; SIZE] {
143 fn from(salt: $i) -> [u8; SIZE] {
144 salt.0.to_be_bytes()
145 }
146 }
147
148 impl From<$i> for $t {
149 fn from(salt: $i) -> $t {
150 salt.0
151 }
152 }
153
154 impl TryFrom<&[u8]> for $i {
155 type Error = TryFromSliceError;
156
157 fn try_from(bytes: &[u8]) -> Result<$i, TryFromSliceError> {
158 <[u8; SIZE]>::try_from(bytes).map(|b| b.into())
159 }
160 }
161
162 impl fmt::LowerHex for $i {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 if f.alternate() {
165 write!(f, "0x")?
166 }
167
168 let bytes = self.0.to_be_bytes();
169 match f.width() {
170 Some(w) if w > 0 => {
171 bytes.chunks(2 * bytes.len() / w).try_for_each(|c| {
172 write!(f, "{:02x}", c.iter().fold(0u8, |acc, x| acc ^ x))
173 })
174 }
175
176 _ => bytes.iter().try_for_each(|b| write!(f, "{:02x}", &b)),
177 }
178 }
179 }
180
181 impl fmt::UpperHex for $i {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 if f.alternate() {
184 write!(f, "0x")?
185 }
186
187 let bytes = self.0.to_be_bytes();
188 match f.width() {
189 Some(w) if w > 0 => {
190 bytes.chunks(2 * bytes.len() / w).try_for_each(|c| {
191 write!(f, "{:02X}", c.iter().fold(0u8, |acc, x| acc ^ x))
192 })
193 }
194
195 _ => bytes.iter().try_for_each(|b| write!(f, "{:02X}", &b)),
196 }
197 }
198 }
199
200 impl fmt::Debug for $i {
201 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
202 <Self as fmt::LowerHex>::fmt(&self, f)
203 }
204 }
205
206 impl fmt::Display for $i {
207 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
208 <Self as fmt::LowerHex>::fmt(&self, f)
209 }
210 }
211
212 impl str::FromStr for $i {
213 type Err = &'static str;
214
215 fn from_str(s: &str) -> Result<Self, Self::Err> {
216 const ERR: &str = concat!("Invalid encoded byte in ", stringify!($i));
217 let mut ret = <[u8; SIZE]>::default();
218 let s = s.strip_prefix("0x").unwrap_or(s);
219 hex::decode_to_slice(&s, &mut ret).map_err(|_| ERR)?;
220 Ok(ret.into())
221 }
222 }
223 };
224 };
225}
226
227key!(BlockHeight, u32);
228key!(ChainId, u64);
229
230impl BlockHeight {
231 pub fn succ(self) -> Option<BlockHeight> {
233 Some(Self(self.0.checked_add(1)?))
234 }
235
236 pub fn pred(self) -> Option<BlockHeight> {
238 Some(Self(self.0.checked_sub(1)?))
239 }
240}