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(&self.as_u128()).finish()
33    }
34}
35
36impl fmt::Display for Balance {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        self.as_u128().fmt(f)
39    }
40}
41
42impl Ord for Balance {
43    #[inline(always)]
44    fn cmp(&self, other: &Balance) -> Ordering {
45        self.as_u128().cmp(&other.as_u128())
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::new(self.as_u128().add(rhs.as_u128()))
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::new(self.as_u128().sub(rhs.as_u128()))
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::new(<u128 as Mul<Rhs>>::mul(self.as_u128(), 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::new(<u128 as Div<Rhs>>::div(self.as_u128(), 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 From<u128> for Balance {
141    #[inline(always)]
142    fn from(value: u128) -> Self {
143        Self::new(value)
144    }
145}
146
147impl From<Balance> for u128 {
148    #[inline(always)]
149    fn from(value: Balance) -> Self {
150        value.as_u128()
151    }
152}
153
154impl Balance {
155    /// Minimum balance
156    pub const MIN: Self = Self::new(0);
157    /// Maximum balance
158    pub const MAX: Self = Self::new(u128::MAX);
159
160    /// Create a value from `u128`
161    #[inline(always)]
162    pub const fn new(n: u128) -> Self {
163        let mut result = MaybeUninit::<Self>::uninit();
164        // SAFETY: correct size, valid pointer, and all bits are valid
165        unsafe {
166            result.as_mut_ptr().cast::<u128>().write_unaligned(n);
167            result.assume_init()
168        }
169    }
170
171    /// Turn value into `u128`
172    #[inline(always)]
173    pub const fn as_u128(self) -> u128 {
174        // SAFETY: correct size, valid pointer, and all bits are valid
175        unsafe { ptr::from_ref(&self).cast::<u128>().read_unaligned() }
176    }
177}