1use alloc::vec::Vec;
4use core::fmt;
5
6#[cfg(feature = "datasize")]
7use datasize::DataSize;
8use serde::{Deserialize, Serialize};
9
10use crate::{
11 bytesrepr::{self, FromBytes, ToBytes},
12 Gas, U512,
13};
14
15#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
17#[cfg_attr(feature = "datasize", derive(DataSize))]
18pub struct Motes(U512);
19
20impl Motes {
21 pub const MAX: Motes = Motes(U512::MAX);
23
24 pub fn new<T: Into<U512>>(value: T) -> Self {
26 Motes(value.into())
27 }
28
29 pub const fn zero() -> Self {
31 Motes(U512::zero())
32 }
33
34 pub fn checked_add(&self, rhs: Self) -> Option<Self> {
36 self.0.checked_add(rhs.value()).map(Self::new)
37 }
38
39 pub fn checked_sub(&self, rhs: Self) -> Option<Self> {
41 self.0.checked_sub(rhs.value()).map(Self::new)
42 }
43
44 pub fn checked_mul(&self, rhs: Self) -> Option<Self> {
47 self.0.checked_mul(rhs.value()).map(Self::new)
48 }
49
50 pub fn checked_div(&self, rhs: Self) -> Option<Self> {
52 self.0.checked_div(rhs.value()).map(Self::new)
53 }
54
55 pub fn value(&self) -> U512 {
57 self.0
58 }
59
60 pub fn from_gas(gas: Gas, conv_rate: u8) -> Option<Self> {
64 gas.value()
65 .checked_mul(U512::from(conv_rate))
66 .map(Self::new)
67 }
68
69 pub fn from_price(amount: U512, price: u8) -> Option<Self> {
73 amount.checked_mul(U512::from(price)).map(Self::new)
74 }
75}
76
77impl fmt::Display for Motes {
78 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79 write!(f, "{:?}", self.0)
80 }
81}
82
83impl ToBytes for Motes {
84 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
85 self.0.to_bytes()
86 }
87
88 fn serialized_length(&self) -> usize {
89 self.0.serialized_length()
90 }
91}
92
93impl FromBytes for Motes {
94 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
95 let (value, remainder) = FromBytes::from_bytes(bytes)?;
96 Ok((Motes(value), remainder))
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use crate::U512;
103
104 use crate::{Gas, Motes};
105
106 #[test]
107 fn should_be_able_to_get_instance_of_motes() {
108 let initial_value = 1;
109 let motes = Motes::new(initial_value);
110 assert_eq!(
111 initial_value,
112 motes.value().as_u64(),
113 "should have equal value"
114 )
115 }
116
117 #[test]
118 fn should_be_able_to_compare_two_instances_of_motes() {
119 let left_motes = Motes::new(1);
120 let right_motes = Motes::new(1);
121 assert_eq!(left_motes, right_motes, "should be equal");
122 let right_motes = Motes::new(2);
123 assert_ne!(left_motes, right_motes, "should not be equal")
124 }
125
126 #[test]
127 fn should_be_able_to_add_two_instances_of_motes() {
128 let left_motes = Motes::new(1);
129 let right_motes = Motes::new(1);
130 let expected_motes = Motes::new(2);
131 assert_eq!(
132 left_motes.checked_add(right_motes),
133 Some(expected_motes),
134 "should be equal"
135 )
136 }
137
138 #[test]
139 fn should_be_able_to_subtract_two_instances_of_motes() {
140 let left_motes = Motes::new(1);
141 let right_motes = Motes::new(1);
142 let expected_motes = Motes::new(0);
143 assert_eq!(
144 left_motes.checked_sub(right_motes),
145 Some(expected_motes),
146 "should be equal"
147 )
148 }
149
150 #[test]
151 fn should_be_able_to_multiply_two_instances_of_motes() {
152 let left_motes = Motes::new(100);
153 let right_motes = Motes::new(10);
154 let expected_motes = Motes::new(1000);
155 assert_eq!(
156 left_motes.checked_mul(right_motes),
157 Some(expected_motes),
158 "should be equal"
159 )
160 }
161
162 #[test]
163 fn should_be_able_to_divide_two_instances_of_motes() {
164 let left_motes = Motes::new(1000);
165 let right_motes = Motes::new(100);
166 let expected_motes = Motes::new(10);
167 assert_eq!(
168 left_motes.checked_div(right_motes),
169 Some(expected_motes),
170 "should be equal"
171 )
172 }
173
174 #[test]
175 fn should_be_able_to_convert_from_motes() {
176 let gas = Gas::new(100);
177 let motes = Motes::from_gas(gas, 10).expect("should have value");
178 let expected_motes = Motes::new(1000);
179 assert_eq!(motes, expected_motes, "should be equal")
180 }
181
182 #[test]
183 fn should_be_able_to_default() {
184 let motes = Motes::default();
185 let expected_motes = Motes::new(0);
186 assert_eq!(motes, expected_motes, "should be equal")
187 }
188
189 #[test]
190 fn should_be_able_to_compare_relative_value() {
191 let left_motes = Motes::new(100);
192 let right_motes = Motes::new(10);
193 assert!(left_motes > right_motes, "should be gt");
194 let right_motes = Motes::new(100);
195 assert!(left_motes >= right_motes, "should be gte");
196 assert!(left_motes <= right_motes, "should be lte");
197 let left_motes = Motes::new(10);
198 assert!(left_motes < right_motes, "should be lt");
199 }
200
201 #[test]
202 fn should_default() {
203 let left_motes = Motes::new(0);
204 let right_motes = Motes::default();
205 assert_eq!(left_motes, right_motes, "should be equal");
206 let u512 = U512::zero();
207 assert_eq!(left_motes.value(), u512, "should be equal");
208 }
209
210 #[test]
211 fn should_support_checked_mul_from_gas() {
212 let gas = Gas::new(U512::MAX);
213 let conv_rate = 10;
214 let maybe = Motes::from_gas(gas, conv_rate);
215 assert!(maybe.is_none(), "should be none due to overflow");
216 }
217}