rustabi/token/
token.rs

1//! Sophon ABI params.
2use std::fmt;
3use hex::ToHex;
4use {ParamType, Address, FixedBytes, Bytes, Uint};
5
6/// Sophon ABI params.
7#[derive(Debug, PartialEq, Clone)]
8pub enum Token {
9	/// Address.
10	///
11	/// solidity name: address
12	/// Encoded to left padded [0u8; 32].
13	Address(Address),
14	/// Vector of bytes with known size.
15	///
16	/// solidity name eg.: bytes8, bytes32, bytes64, bytes1024
17	/// Encoded to right padded [0u8; ((N + 31) / 32) * 32].
18	FixedBytes(FixedBytes),
19	/// Vector of bytes of unknown size.
20	///
21	/// solidity name: bytes
22	/// Encoded in two parts.
23	/// Init part: offset of 'closing part`.
24	/// Closing part: encoded length followed by encoded right padded bytes.
25	Bytes(Bytes),
26	/// Signed integer.
27	///
28	/// solidity name: int
29	Int(Uint),
30	/// Unisnged integer.
31	///
32	/// solidity name: uint
33	Uint(Uint),
34	/// Boolean value.
35	///
36	/// solidity name: bool
37	/// Encoded as left padded [0u8; 32], where last bit represents boolean value.
38	Bool(bool),
39	/// String.
40	///
41	/// solidity name: string
42	/// Encoded in the same way as bytes. Must be utf8 compliant.
43	String(String),
44	/// Array with known size.
45	///
46	/// solidity name eg.: int[3], bool[3], address[][8]
47	/// Encoding of array is equal to encoding of consecutive elements of array.
48	FixedArray(Vec<Token>),
49	/// Array of params with unknown size.
50	///
51	/// solidity name eg. int[], bool[], address[5][]
52	Array(Vec<Token>),
53}
54
55impl fmt::Display for Token {
56	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57		match *self {
58			Token::Bool(b) => write!(f, "{}", b),
59			Token::String(ref s) => write!(f, "{}", s),
60			Token::Address(ref a) => write!(f, "{:x}", a),
61			Token::Bytes(ref bytes) | Token::FixedBytes(ref bytes) => write!(f, "{}", bytes.to_hex::<String>()),
62			Token::Uint(ref i) | Token::Int(ref i) => write!(f, "{:x}", i),
63			Token::Array(ref arr) | Token::FixedArray(ref arr) => {
64				let s = arr.iter()
65					.map(|ref t| format!("{}", t))
66					.collect::<Vec<String>>()
67					.join(",");
68
69				write!(f, "[{}]", s)
70			}
71		}
72	}
73}
74
75impl Token {
76	/// Check whether the type of the token matches the given parameter type.
77	///
78	/// Numeric types (`Int` and `Uint`) type check if the size of the token
79	/// type is of greater or equal size than the provided parameter type.
80	pub fn type_check(&self, param_type: &ParamType) -> bool {
81		match *self {
82			Token::Address(_) => *param_type == ParamType::Address,
83			Token::Bytes(_) => *param_type == ParamType::Bytes,
84			Token::Int(_) =>
85				if let ParamType::Int(_) = *param_type {
86					true
87				} else {
88					false
89				},
90			Token::Uint(_) =>
91				if let ParamType::Uint(_) = *param_type {
92					true
93				} else {
94					false
95				},
96			Token::Bool(_) => *param_type == ParamType::Bool,
97			Token::String(_) => *param_type == ParamType::String,
98			Token::FixedBytes(ref bytes) =>
99				if let ParamType::FixedBytes(size) = *param_type {
100					size >= bytes.len()
101				} else {
102					false
103				},
104			Token::Array(ref tokens) =>
105				if let ParamType::Array(ref param_type) = *param_type {
106					tokens.iter().all(|t| t.type_check(param_type))
107				} else {
108					false
109				},
110			Token::FixedArray(ref tokens) =>
111				if let ParamType::FixedArray(ref param_type, size) = *param_type {
112					size == tokens.len() && tokens.iter().all(|t| t.type_check(param_type))
113				} else {
114					false
115				},
116		}
117	}
118
119	/// Converts token to...
120	pub fn to_address(self) -> Option<Address> {
121		match self {
122			Token::Address(address) => Some(address),
123			_ => None,
124		}
125	}
126
127	/// Converts token to...
128	pub fn to_fixed_bytes(self) -> Option<Vec<u8>> {
129		match self {
130			Token::FixedBytes(bytes) => Some(bytes),
131			_ => None,
132		}
133	}
134
135	/// Converts token to...
136	pub fn to_bytes(self) -> Option<Vec<u8>> {
137		match self {
138			Token::Bytes(bytes) => Some(bytes),
139			_ => None,
140		}
141	}
142
143	/// Converts token to...
144	pub fn to_int(self) -> Option<Uint> {
145		match self {
146			Token::Int(int) => Some(int),
147			_ => None,
148		}
149	}
150
151	/// Converts token to...
152	pub fn to_uint(self) -> Option<Uint> {
153		match self {
154			Token::Uint(uint) => Some(uint),
155			_ => None,
156		}
157	}
158
159	/// Converts token to...
160	pub fn to_bool(self) -> Option<bool> {
161		match self {
162			Token::Bool(b) => Some(b),
163			_ => None,
164		}
165	}
166
167	/// Converts token to...
168	pub fn to_string(self) -> Option<String> {
169		match self {
170			Token::String(s) => Some(s),
171			_ => None,
172		}
173	}
174
175	/// Converts token to...
176	pub fn to_fixed_array(self) -> Option<Vec<Token>> {
177		match self {
178			Token::FixedArray(arr) => Some(arr),
179			_ => None,
180		}
181	}
182
183	/// Converts token to...
184	pub fn to_array(self) -> Option<Vec<Token>> {
185		match self {
186			Token::Array(arr) => Some(arr),
187			_ => None,
188		}
189	}
190
191	/// Check if all the types of the tokens match the given parameter types.
192	pub fn types_check(tokens: &[Token], param_types: &[ParamType]) -> bool {
193		param_types.len() == tokens.len() && {
194			param_types.iter().zip(tokens).all(|(param_type, token)| {
195				token.type_check(param_type)
196			})
197		}
198	}
199}
200
201
202#[cfg(test)]
203mod tests {
204	use {Token, ParamType};
205
206	#[test]
207	fn test_type_check() {
208		fn assert_type_check(tokens: Vec<Token>, param_types: Vec<ParamType>) {
209			assert!(Token::types_check(&tokens, &param_types))
210		}
211
212		fn assert_not_type_check(tokens: Vec<Token>, param_types: Vec<ParamType>) {
213			assert!(!Token::types_check(&tokens, &param_types))
214		}
215
216		assert_type_check(vec![Token::Uint(0.into()), Token::Bool(false)], vec![ParamType::Uint(256), ParamType::Bool]);
217		assert_type_check(vec![Token::Uint(0.into()), Token::Bool(false)], vec![ParamType::Uint(32), ParamType::Bool]);
218
219		assert_not_type_check(vec![Token::Uint(0.into())], vec![ParamType::Uint(32), ParamType::Bool]);
220		assert_not_type_check(vec![Token::Uint(0.into()), Token::Bool(false)], vec![ParamType::Uint(32)]);
221		assert_not_type_check(vec![Token::Bool(false), Token::Uint(0.into())], vec![ParamType::Uint(32), ParamType::Bool]);
222
223		assert_type_check(vec![Token::FixedBytes(vec![0, 0, 0, 0])], vec![ParamType::FixedBytes(4)]);
224		assert_type_check(vec![Token::FixedBytes(vec![0, 0, 0])], vec![ParamType::FixedBytes(4)]);
225		assert_not_type_check(vec![Token::FixedBytes(vec![0, 0, 0, 0])], vec![ParamType::FixedBytes(3)]);
226
227		assert_type_check(vec![Token::Array(vec![Token::Bool(false), Token::Bool(true)])], vec![ParamType::Array(Box::new(ParamType::Bool))]);
228		assert_not_type_check(vec![Token::Array(vec![Token::Bool(false), Token::Uint(0.into())])], vec![ParamType::Array(Box::new(ParamType::Bool))]);
229		assert_not_type_check(vec![Token::Array(vec![Token::Bool(false), Token::Bool(true)])], vec![ParamType::Array(Box::new(ParamType::Address))]);
230
231		assert_type_check(vec![Token::FixedArray(vec![Token::Bool(false), Token::Bool(true)])], vec![ParamType::FixedArray(Box::new(ParamType::Bool), 2)]);
232		assert_not_type_check(vec![Token::FixedArray(vec![Token::Bool(false), Token::Bool(true)])], vec![ParamType::FixedArray(Box::new(ParamType::Bool), 3)]);
233		assert_not_type_check(vec![Token::FixedArray(vec![Token::Bool(false), Token::Uint(0.into())])], vec![ParamType::FixedArray(Box::new(ParamType::Bool), 2)]);
234		assert_not_type_check(vec![Token::FixedArray(vec![Token::Bool(false), Token::Bool(true)])], vec![ParamType::FixedArray(Box::new(ParamType::Address), 2)]);
235	}
236}