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    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        f.debug_tuple("Balance").field(&self.into_u128()).finish()
30    }
31}
32
33impl fmt::Display for Balance {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        self.into_u128().fmt(f)
36    }
37}
38
39impl Ord for Balance {
40    #[inline(always)]
41    fn cmp(&self, other: &Balance) -> Ordering {
42        self.into_u128().cmp(&other.into_u128())
43    }
44}
45
46impl PartialOrd for Balance {
47    #[inline(always)]
48    fn partial_cmp(&self, other: &Balance) -> Option<Ordering> {
49        Some(self.cmp(other))
50    }
51}
52
53impl Add for Balance {
54    type Output = Balance;
55
56    #[inline(always)]
57    #[track_caller]
58    fn add(self, rhs: Balance) -> Balance {
59        Self::from_u128(self.into_u128().add(rhs.into_u128()))
60    }
61}
62
63impl AddAssign for Balance {
64    #[inline(always)]
65    #[track_caller]
66    fn add_assign(&mut self, rhs: Balance) {
67        *self = *self + rhs;
68    }
69}
70
71impl Sub for Balance {
72    type Output = Balance;
73
74    #[inline(always)]
75    #[track_caller]
76    fn sub(self, rhs: Balance) -> Balance {
77        Self::from_u128(self.into_u128().sub(rhs.into_u128()))
78    }
79}
80
81impl SubAssign for Balance {
82    #[inline(always)]
83    #[track_caller]
84    fn sub_assign(&mut self, rhs: Balance) {
85        *self = *self - rhs;
86    }
87}
88
89impl<Rhs> Mul<Rhs> for Balance
90where
91    u128: Mul<Rhs, Output = u128>,
92{
93    type Output = Balance;
94
95    #[inline(always)]
96    #[track_caller]
97    fn mul(self, rhs: Rhs) -> Balance {
98        Self::from_u128(<u128 as Mul<Rhs>>::mul(self.into_u128(), rhs))
99    }
100}
101
102impl<Rhs> MulAssign<Rhs> for Balance
103where
104    u128: Mul<Rhs, Output = u128>,
105{
106    #[inline(always)]
107    #[track_caller]
108    fn mul_assign(&mut self, rhs: Rhs) {
109        *self = *self * rhs;
110    }
111}
112
113impl<Rhs> Div<Rhs> for Balance
114where
115    u128: Div<Rhs, Output = u128>,
116{
117    type Output = Balance;
118
119    #[inline(always)]
120    #[track_caller]
121    fn div(self, rhs: Rhs) -> Balance {
122        Self::from_u128(<u128 as Div<Rhs>>::div(self.into_u128(), rhs))
123    }
124}
125
126impl<Rhs> DivAssign<Rhs> for Balance
127where
128    u128: Div<Rhs, Output = u128>,
129{
130    #[inline(always)]
131    #[track_caller]
132    fn div_assign(&mut self, rhs: Rhs) {
133        *self = *self / rhs;
134    }
135}
136
137impl From<u128> for Balance {
138    #[inline(always)]
139    fn from(value: u128) -> Self {
140        Self::from_u128(value)
141    }
142}
143
144impl From<Balance> for u128 {
145    #[inline(always)]
146    fn from(value: Balance) -> Self {
147        value.into_u128()
148    }
149}
150
151impl Balance {
152    pub const MIN: Self = Self::from_u128(0);
153    pub const MAX: Self = Self::from_u128(u128::MAX);
154
155    /// Turn value into `u128`
156    #[inline(always)]
157    pub const fn into_u128(self) -> u128 {
158        // SAFETY: correct size, valid pointer, and all bits are valid
159        unsafe { ptr::from_ref(&self).cast::<u128>().read_unaligned() }
160    }
161
162    /// Create a value from `u128`
163    #[inline(always)]
164    pub const fn from_u128(n: u128) -> Self {
165        let mut result = MaybeUninit::<Self>::uninit();
166        // SAFETY: correct size, valid pointer, and all bits are valid
167        unsafe {
168            result.as_mut_ptr().cast::<u128>().write_unaligned(n);
169            result.assume_init()
170        }
171    }
172}