ab_contracts_common/
balance.rs

1use ab_contracts_io_type::metadata::IoTypeMetadataKind;
2use ab_contracts_io_type::trivial_type::TrivialType;
3use core::cmp::Ordering;
4use core::mem::MaybeUninit;
5use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
6use core::{fmt, ptr};
7
8/// Logically the same as `u128`, but aligned to `8` bytes instead of `16`.
9///
10/// Byte layout is the same as `u128`, just alignment is different
11#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
12#[repr(C)]
13pub struct Balance(u64, u64);
14
15unsafe impl TrivialType for Balance {
16    const METADATA: &[u8] = &[IoTypeMetadataKind::Balance as u8];
17}
18
19// Ensure this never mismatches with code in `ab-contracts-io-type` despite being in different crate
20const _: () = {
21    let (type_details, _metadata) = IoTypeMetadataKind::type_details(Balance::METADATA)
22        .expect("Statically correct metadata; qed");
23    assert!(size_of::<Balance>() == type_details.recommended_capacity as usize);
24    assert!(align_of::<Balance>() == type_details.alignment.get() as usize);
25};
26
27impl fmt::Debug for Balance {
28    #[inline(always)]
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        f.debug_tuple("Balance").field(&self.into_u128()).finish()
31    }
32}
33
34impl fmt::Display for Balance {
35    #[inline(always)]
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        self.into_u128().fmt(f)
38    }
39}
40
41impl Ord for Balance {
42    #[inline(always)]
43    fn cmp(&self, other: &Balance) -> Ordering {
44        self.into_u128().cmp(&other.into_u128())
45    }
46}
47
48impl PartialOrd for Balance {
49    #[inline(always)]
50    fn partial_cmp(&self, other: &Balance) -> Option<Ordering> {
51        Some(self.cmp(other))
52    }
53}
54
55impl Add for Balance {
56    type Output = Balance;
57
58    #[inline(always)]
59    #[track_caller]
60    fn add(self, rhs: Balance) -> Balance {
61        Self::from_u128(self.into_u128().add(rhs.into_u128()))
62    }
63}
64
65impl AddAssign for Balance {
66    #[inline(always)]
67    #[track_caller]
68    fn add_assign(&mut self, rhs: Balance) {
69        *self = *self + rhs;
70    }
71}
72
73impl Sub for Balance {
74    type Output = Balance;
75
76    #[inline(always)]
77    #[track_caller]
78    fn sub(self, rhs: Balance) -> Balance {
79        Self::from_u128(self.into_u128().sub(rhs.into_u128()))
80    }
81}
82
83impl SubAssign for Balance {
84    #[inline(always)]
85    #[track_caller]
86    fn sub_assign(&mut self, rhs: Balance) {
87        *self = *self - rhs;
88    }
89}
90
91impl<Rhs> Mul<Rhs> for Balance
92where
93    u128: Mul<Rhs, Output = u128>,
94{
95    type Output = Balance;
96
97    #[inline(always)]
98    #[track_caller]
99    fn mul(self, rhs: Rhs) -> Balance {
100        Self::from_u128(<u128 as Mul<Rhs>>::mul(self.into_u128(), rhs))
101    }
102}
103
104impl<Rhs> MulAssign<Rhs> for Balance
105where
106    u128: Mul<Rhs, Output = u128>,
107{
108    #[inline(always)]
109    #[track_caller]
110    fn mul_assign(&mut self, rhs: Rhs) {
111        *self = *self * rhs;
112    }
113}
114
115impl<Rhs> Div<Rhs> for Balance
116where
117    u128: Div<Rhs, Output = u128>,
118{
119    type Output = Balance;
120
121    #[inline(always)]
122    #[track_caller]
123    fn div(self, rhs: Rhs) -> Balance {
124        Self::from_u128(<u128 as Div<Rhs>>::div(self.into_u128(), rhs))
125    }
126}
127
128impl<Rhs> DivAssign<Rhs> for Balance
129where
130    u128: Div<Rhs, Output = u128>,
131{
132    #[inline(always)]
133    #[track_caller]
134    fn div_assign(&mut self, rhs: Rhs) {
135        *self = *self / rhs;
136    }
137}
138
139impl From<u128> for Balance {
140    #[inline(always)]
141    fn from(value: u128) -> Self {
142        Self::from_u128(value)
143    }
144}
145
146impl From<Balance> for u128 {
147    #[inline(always)]
148    fn from(value: Balance) -> Self {
149        value.into_u128()
150    }
151}
152
153impl Balance {
154    pub const MIN: Self = Self::from_u128(0);
155    pub const MAX: Self = Self::from_u128(u128::MAX);
156
157    /// Turn value into `u128`
158    #[inline(always)]
159    pub const fn into_u128(self) -> u128 {
160        // SAFETY: correct size, valid pointer, and all bits are valid
161        unsafe { ptr::from_ref(&self).cast::<u128>().read_unaligned() }
162    }
163
164    /// Create a value from `u128`
165    #[inline(always)]
166    pub const fn from_u128(n: u128) -> Self {
167        let mut result = MaybeUninit::<Self>::uninit();
168        // SAFETY: correct size, valid pointer, and all bits are valid
169        unsafe {
170            result.as_mut_ptr().cast::<u128>().write_unaligned(n);
171            result.assume_init()
172        }
173    }
174}