Skip to main content

ab_core_primitives/
balance.rs

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