1use core::fmt;
12
13#[cfg(feature = "serde")]
14use serde::{Deserialize, Serialize};
15
16#[cfg(not(feature = "std"))]
17use crate::no_std_prelude::*;
18use crate::{Address, Bytes, FixedBytes, Int, ParamType, Uint};
19
20#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
22#[derive(Debug, PartialEq, Clone)]
23pub enum Token {
24 Address(Address),
29 FixedBytes(FixedBytes),
34 Bytes(Bytes),
41 Int(Int),
45 Uint(Uint),
49 Bool(bool),
54 String(String),
59 FixedArray(Vec<Token>),
64 Array(Vec<Token>),
68 Tuple(Vec<Token>),
72}
73
74impl fmt::Display for Token {
75 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76 match *self {
77 Token::Bool(b) => write!(f, "{b}"),
78 Token::String(ref s) => write!(f, "{s}"),
79 Token::Address(ref a) => write!(f, "{a:x}"),
80 Token::Bytes(ref bytes) | Token::FixedBytes(ref bytes) => write!(f, "{}", hex::encode(bytes)),
81 Token::Uint(ref i) | Token::Int(ref i) => write!(f, "{i:x}"),
82 Token::Array(ref arr) | Token::FixedArray(ref arr) => {
83 let s = arr.iter().map(|ref t| format!("{t}")).collect::<Vec<String>>().join(",");
84
85 write!(f, "[{s}]")
86 }
87 Token::Tuple(ref s) => {
88 let s = s.iter().map(|ref t| format!("{t}")).collect::<Vec<String>>().join(",");
89
90 write!(f, "({s})")
91 }
92 }
93 }
94}
95
96impl Token {
97 pub fn type_check(&self, param_type: &ParamType) -> bool {
102 match *self {
103 Token::Address(_) => *param_type == ParamType::Address,
104 Token::Bytes(_) => *param_type == ParamType::Bytes,
105 Token::Int(_) => {
106 matches!(*param_type, ParamType::Int(_))
107 }
108 Token::Uint(_) => {
109 matches!(*param_type, ParamType::Uint(_))
110 }
111 Token::Bool(_) => *param_type == ParamType::Bool,
112 Token::String(_) => *param_type == ParamType::String,
113 Token::FixedBytes(ref bytes) => {
114 if let ParamType::FixedBytes(size) = *param_type {
115 size >= bytes.len()
116 } else {
117 false
118 }
119 }
120 Token::Array(ref tokens) => {
121 if let ParamType::Array(ref param_type) = *param_type {
122 tokens.iter().all(|t| t.type_check(param_type))
123 } else {
124 false
125 }
126 }
127 Token::FixedArray(ref tokens) => {
128 if let ParamType::FixedArray(ref param_type, size) = *param_type {
129 size == tokens.len() && tokens.iter().all(|t| t.type_check(param_type))
130 } else {
131 false
132 }
133 }
134 Token::Tuple(ref tokens) => {
135 if let ParamType::Tuple(ref param_type) = *param_type {
136 tokens.iter().enumerate().all(|(i, t)| t.type_check(¶m_type[i]))
137 } else {
138 false
139 }
140 }
141 }
142 }
143
144 pub fn into_address(self) -> Option<Address> {
146 match self {
147 Token::Address(address) => Some(address),
148 _ => None,
149 }
150 }
151
152 pub fn into_fixed_bytes(self) -> Option<Vec<u8>> {
154 match self {
155 Token::FixedBytes(bytes) => Some(bytes),
156 _ => None,
157 }
158 }
159
160 pub fn into_bytes(self) -> Option<Vec<u8>> {
162 match self {
163 Token::Bytes(bytes) => Some(bytes),
164 _ => None,
165 }
166 }
167
168 pub fn into_int(self) -> Option<Int> {
170 match self {
171 Token::Int(int) => Some(int),
172 _ => None,
173 }
174 }
175
176 pub fn into_uint(self) -> Option<Uint> {
178 match self {
179 Token::Uint(uint) => Some(uint),
180 _ => None,
181 }
182 }
183
184 pub fn into_bool(self) -> Option<bool> {
186 match self {
187 Token::Bool(b) => Some(b),
188 _ => None,
189 }
190 }
191
192 pub fn into_string(self) -> Option<String> {
194 match self {
195 Token::String(s) => Some(s),
196 _ => None,
197 }
198 }
199
200 pub fn into_fixed_array(self) -> Option<Vec<Token>> {
202 match self {
203 Token::FixedArray(arr) => Some(arr),
204 _ => None,
205 }
206 }
207
208 pub fn into_array(self) -> Option<Vec<Token>> {
210 match self {
211 Token::Array(arr) => Some(arr),
212 _ => None,
213 }
214 }
215
216 pub fn into_tuple(self) -> Option<Vec<Token>> {
218 match self {
219 Token::Tuple(tuple) => Some(tuple),
220 _ => None,
221 }
222 }
223
224 pub fn types_check(tokens: &[Token], param_types: &[ParamType]) -> bool {
226 param_types.len() == tokens.len() && {
227 param_types.iter().zip(tokens).all(|(param_type, token)| token.type_check(param_type))
228 }
229 }
230
231 pub fn is_dynamic(&self) -> bool {
233 match self {
234 Token::Bytes(_) | Token::String(_) | Token::Array(_) => true,
235 Token::FixedArray(tokens) => tokens.iter().any(|token| token.is_dynamic()),
236 Token::Tuple(tokens) => tokens.iter().any(|token| token.is_dynamic()),
237 _ => false,
238 }
239 }
240}
241
242#[cfg(test)]
243mod tests {
244 #[cfg(not(feature = "std"))]
245 use crate::no_std_prelude::*;
246 use crate::{ParamType, Token};
247
248 #[test]
249 fn test_type_check() {
250 fn assert_type_check(tokens: Vec<Token>, param_types: Vec<ParamType>) {
251 assert!(Token::types_check(&tokens, ¶m_types))
252 }
253
254 fn assert_not_type_check(tokens: Vec<Token>, param_types: Vec<ParamType>) {
255 assert!(!Token::types_check(&tokens, ¶m_types))
256 }
257
258 assert_type_check(vec![Token::Uint(0.into()), Token::Bool(false)], vec![ParamType::Uint(256), ParamType::Bool]);
259 assert_type_check(vec![Token::Uint(0.into()), Token::Bool(false)], vec![ParamType::Uint(32), ParamType::Bool]);
260
261 assert_not_type_check(vec![Token::Uint(0.into())], vec![ParamType::Uint(32), ParamType::Bool]);
262 assert_not_type_check(vec![Token::Uint(0.into()), Token::Bool(false)], vec![ParamType::Uint(32)]);
263 assert_not_type_check(
264 vec![Token::Bool(false), Token::Uint(0.into())],
265 vec![ParamType::Uint(32), ParamType::Bool],
266 );
267
268 assert_type_check(vec![Token::FixedBytes(vec![0, 0, 0, 0])], vec![ParamType::FixedBytes(4)]);
269 assert_type_check(vec![Token::FixedBytes(vec![0, 0, 0])], vec![ParamType::FixedBytes(4)]);
270 assert_not_type_check(vec![Token::FixedBytes(vec![0, 0, 0, 0])], vec![ParamType::FixedBytes(3)]);
271
272 assert_type_check(
273 vec![Token::Array(vec![Token::Bool(false), Token::Bool(true)])],
274 vec![ParamType::Array(Box::new(ParamType::Bool))],
275 );
276 assert_not_type_check(
277 vec![Token::Array(vec![Token::Bool(false), Token::Uint(0.into())])],
278 vec![ParamType::Array(Box::new(ParamType::Bool))],
279 );
280 assert_not_type_check(
281 vec![Token::Array(vec![Token::Bool(false), Token::Bool(true)])],
282 vec![ParamType::Array(Box::new(ParamType::Address))],
283 );
284
285 assert_type_check(
286 vec![Token::FixedArray(vec![Token::Bool(false), Token::Bool(true)])],
287 vec![ParamType::FixedArray(Box::new(ParamType::Bool), 2)],
288 );
289 assert_not_type_check(
290 vec![Token::FixedArray(vec![Token::Bool(false), Token::Bool(true)])],
291 vec![ParamType::FixedArray(Box::new(ParamType::Bool), 3)],
292 );
293 assert_not_type_check(
294 vec![Token::FixedArray(vec![Token::Bool(false), Token::Uint(0.into())])],
295 vec![ParamType::FixedArray(Box::new(ParamType::Bool), 2)],
296 );
297 assert_not_type_check(
298 vec![Token::FixedArray(vec![Token::Bool(false), Token::Bool(true)])],
299 vec![ParamType::FixedArray(Box::new(ParamType::Address), 2)],
300 );
301 }
302
303 #[test]
304 fn test_is_dynamic() {
305 assert!(!Token::Address("0000000000000000000000000000000000000000".parse().unwrap()).is_dynamic());
306 assert!(Token::Bytes(vec![0, 0, 0, 0]).is_dynamic());
307 assert!(!Token::FixedBytes(vec![0, 0, 0, 0]).is_dynamic());
308 assert!(!Token::Uint(0.into()).is_dynamic());
309 assert!(!Token::Int(0.into()).is_dynamic());
310 assert!(!Token::Bool(false).is_dynamic());
311 assert!(Token::String("".into()).is_dynamic());
312 assert!(Token::Array(vec![Token::Bool(false)]).is_dynamic());
313 assert!(!Token::FixedArray(vec![Token::Uint(0.into())]).is_dynamic());
314 assert!(Token::FixedArray(vec![Token::String("".into())]).is_dynamic());
315 assert!(Token::FixedArray(vec![Token::Array(vec![Token::Bool(false)])]).is_dynamic());
316 }
317}