1#[cfg(feature = "codec")]
2pub mod json;
3pub mod rust;
4#[cfg(feature = "codec")]
5pub mod sol;
6#[cfg(feature = "codec")]
7pub mod type_mapping;
8
9use std::path::Path;
10
11use anyhow::Result;
12use serde::{Deserialize, Serialize};
13
14use crate::manifest::Input;
15
16pub use indexmap::map::serde_seq;
17pub use indexmap::IndexMap;
18
19#[cfg(feature = "codec")]
20pub use type_mapping::TypeMapping;
21
22#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
23pub struct Address([u8; 20]);
24
25#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
26pub struct Int256([u64; 4]);
27
28#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
29pub struct Uint256([u64; 4]);
30
31pub trait PointerIndex {
32 type Output;
33 fn ptr(&self, index: &str) -> Option<Self::Output>;
34 fn ptr_assign(&mut self, index: &str, value: Self::Output) -> Result<()>;
35}
36
37#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
38pub enum CliqueValue {
39 Bool(bool),
40 String(String),
41 Bytes(Vec<u8>),
42 Address(Address),
43 Float(f64),
44 Int8(i8),
45 Uint8(u8),
46 Int16(i16),
47 Uint16(u16),
48 Int32(i32),
49 Uint32(u32),
50 Int64(i64),
51 Uint64(u64),
52 Int128(i128),
53 Uint128(u128),
54 Int256(Int256),
55 Uint256(Uint256),
56 Array(Vec<CliqueValue>),
57 Custom(IndexMap<String, CliqueValue>),
58}
59
60impl PointerIndex for CliqueValue {
61 type Output = CliqueValue;
62 fn ptr(&self, index: &str) -> Option<CliqueValue> {
63 let mut cur = self;
64 for part in Path::new(index).iter() {
65 let part = part.to_str().unwrap();
66 if part == "/" {
67 continue;
68 }
69
70 match cur {
71 _ if let Some(v) = cur.as_custom_value() => {
72 cur = v.get(part)?;
73 }
74 _ if let Some(v) = cur.as_array() => {
75 if let Ok(idx) = part.parse::<usize>() {
76 cur = v.get(idx)?;
77 } else {
78 return None;
79 }
80 }
81 _ => return None,
82 }
83 }
84 Some(cur.clone())
85 }
86
87 fn ptr_assign(&mut self, index: &str, value: Self::Output) -> Result<()> {
88 let mut cur = self;
89 for part in Path::new(index).iter() {
90 let part = part.to_str().unwrap();
91 if part == "/" {
92 continue;
93 }
94
95 let v = cur.as_custom_value_mut();
96 if v.is_none() {
97 return Err(anyhow::anyhow!("Can not assign to non-custom type"));
98 }
99 let v = v.unwrap();
100
101 if v.get(part).is_none() {
102 v.insert(part.to_string(), CliqueValue::Custom(IndexMap::new()));
103 }
104
105 cur = v.get_mut(part).unwrap()
106 }
107 *cur = value;
108 Ok(())
109 }
110}
111
112impl CliqueValue {
113 pub fn is_match(&self, clique_type: &CliqueValueType) -> bool {
114 match (self, clique_type) {
115 (CliqueValue::Bool(_), CliqueValueType::Bool) => true,
116 (CliqueValue::String(_), CliqueValueType::String) => true,
117 (CliqueValue::Bytes(_), CliqueValueType::Bytes) => true,
118 (CliqueValue::Address(_), CliqueValueType::Address) => true,
119 (CliqueValue::Float(_), CliqueValueType::Float) => true,
120 (CliqueValue::Int8(_), CliqueValueType::Int8) => true,
121 (CliqueValue::Uint8(_), CliqueValueType::Uint8) => true,
122 (CliqueValue::Int16(_), CliqueValueType::Int16) => true,
123 (CliqueValue::Uint16(_), CliqueValueType::Uint16) => true,
124 (CliqueValue::Int32(_), CliqueValueType::Int32) => true,
125 (CliqueValue::Uint32(_), CliqueValueType::Uint32) => true,
126 (CliqueValue::Int64(_), CliqueValueType::Int64) => true,
127 (CliqueValue::Uint64(_), CliqueValueType::Uint64) => true,
128 (CliqueValue::Int128(_), CliqueValueType::Int128) => true,
129 (CliqueValue::Uint128(_), CliqueValueType::Uint128) => true,
130 (CliqueValue::Int256(_), CliqueValueType::Int256) => true,
131 (CliqueValue::Uint256(_), CliqueValueType::Uint256) => true,
132 (CliqueValue::Array(values), CliqueValueType::Array(type_)) => {
133 values.iter().all(|value| value.is_match(type_))
134 }
135 (CliqueValue::Custom(map), CliqueValueType::Custom(custom_type)) => {
136 let type_map = &custom_type.type_;
137 if map.len() != type_map.len() {
138 return false;
139 }
140 for ((name, value), (type_name, type_)) in map.iter().zip(type_map.iter()) {
141 if name != type_name || !value.is_match(type_) {
142 return false;
143 }
144 }
145 true
146 }
147 _ => false,
148 }
149 }
150
151 pub fn as_array(&self) -> Option<&Vec<CliqueValue>> {
152 match self {
153 Self::Array(arr) => Some(arr),
154 _ => None,
155 }
156 }
157
158 pub fn as_custom_value(&self) -> Option<&IndexMap<String, CliqueValue>> {
159 match self {
160 Self::Custom(map) => Some(&map),
161 _ => None,
162 }
163 }
164
165 pub fn as_custom_value_mut(&mut self) -> Option<&mut IndexMap<String, CliqueValue>> {
166 match self {
167 Self::Custom(map) => Some(map),
168 _ => None,
169 }
170 }
171
172 pub fn into_custom_value(self) -> Option<IndexMap<String, CliqueValue>> {
173 match self {
174 Self::Custom(map) => Some(map),
175 _ => None,
176 }
177 }
178
179 pub fn to_bytes(&self) -> Result<Vec<u8>> {
181 Ok(bincode::serialize(self)?)
182 }
183
184 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
186 Ok(bincode::deserialize(bytes)?)
187 }
188
189 pub fn serialize_map(map: &IndexMap<String, CliqueValue>) -> Result<Vec<u8>> {
190 Ok(bincode::serialize(map)?)
191 }
192
193 pub fn deserialize_map(bytes: &[u8]) -> Result<IndexMap<String, CliqueValue>> {
194 Ok(bincode::deserialize(bytes)?)
195 }
196
197 pub fn serialize_map_to_hex(map: &IndexMap<String, CliqueValue>) -> Result<String> {
198 let bytes = Self::serialize_map(map)?;
199 Ok(hex::encode(bytes))
200 }
201
202 pub fn deserialize_map_from_hex(
203 hex_str: impl AsRef<str>,
204 ) -> Result<IndexMap<String, CliqueValue>> {
205 let bytes = hex::decode(hex_str.as_ref())?;
206 Self::deserialize_map(&bytes)
207 }
208}
209
210#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
211pub struct CustomType {
212 pub name: String,
213 pub type_: IndexMap<String, CliqueValueType>,
214}
215
216impl CustomType {
217 pub fn new(name: String, type_: IndexMap<String, CliqueValueType>) -> Self {
218 Self { name, type_ }
219 }
220
221 pub fn from_map(
222 type_name: &str,
223 map: &IndexMap<String, Input>,
224 custom_types: Option<&IndexMap<String, CustomType>>,
225 ) -> Result<Self> {
226 let mut res = IndexMap::new();
227
228 for (name, input) in map.iter() {
229 let type_ = CliqueValueType::from_str(&input.type_, custom_types)?;
230 res.insert(name.clone(), type_);
231 }
232
233 let custom_type = CustomType::new(type_name.to_string(), res);
234 Ok(custom_type)
235 }
236
237 pub fn from_str_map(
238 type_name: &str,
239 map: &IndexMap<String, String>,
240 custom_types: Option<&IndexMap<String, CustomType>>,
241 ) -> Result<Self> {
242 let mut res = IndexMap::new();
243
244 for (name, type_str) in map.iter() {
245 let type_ = CliqueValueType::from_str(type_str, custom_types)?;
246 res.insert(name.clone(), type_);
247 }
248
249 let custom_type = CustomType::new(type_name.to_string(), res);
250 Ok(custom_type)
251 }
252}
253
254#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
255pub enum CliqueValueType {
256 Bool,
257 String,
258 Bytes,
259 Address,
260 Float,
261 Int8,
262 Uint8,
263 Int16,
264 Uint16,
265 Int32,
266 Uint32,
267 Int64,
268 Uint64,
269 Int128,
270 Uint128,
271 Int256,
272 Uint256,
273 Array(Box<CliqueValueType>),
274 Custom(CustomType),
275}
276
277impl CliqueValueType {
278 pub fn from_str(
279 type_str: impl AsRef<str> + ToString,
280 custom_types: Option<&IndexMap<String, CustomType>>,
281 ) -> Result<Self> {
282 let type_str = type_str.as_ref();
283
284 if let Some(type_str) = type_str.strip_suffix("[]") {
285 if type_str.contains("[]") {
286 anyhow::bail!("Can not nest array");
287 }
288 return Ok(Self::Array(Box::new(Self::from_str(
289 type_str,
290 custom_types,
291 )?)));
292 }
293
294 Ok(match type_str {
295 "bool" => Self::Bool,
296 "string" => Self::String,
297 "bytes" => Self::Bytes,
298 "address" => Self::Address,
299 "float" => Self::Float,
300 "i8" => Self::Int8,
301 "u8" => Self::Uint8,
302 "i16" => Self::Int16,
303 "u16" => Self::Uint16,
304 "i32" => Self::Int32,
305 "u32" => Self::Uint32,
306 "i64" => Self::Int64,
307 "u64" => Self::Uint64,
308 "i128" => Self::Int128,
309 "u128" => Self::Uint128,
310 "i256" => Self::Int256,
311 "u256" => Self::Uint256,
312 other => Self::Custom(
313 custom_types
314 .and_then(|types| types.get(other))
315 .ok_or(anyhow::anyhow!("Invalid type str: {}", type_str))?
316 .clone(),
317 ),
318 })
319 }
320
321 #[cfg(feature = "codec")]
331 pub fn from_json_object(
332 type_name: &str,
333 input_json: serde_json::Value,
334 types_json: serde_json::Value,
335 ) -> Result<Self> {
336 let custom_types = if types_json.is_null() {
337 None
338 } else {
339 let types_map: IndexMap<String, IndexMap<String, String>> =
340 serde_json::from_value(types_json)?;
341 let mut custom_types = None;
342 for (name, map) in types_map.iter() {
343 let new_type = CustomType::from_str_map(name, map, custom_types.as_ref())?;
344 if custom_types.is_none() {
345 custom_types = Some(IndexMap::new());
346 }
347 custom_types
348 .as_mut()
349 .unwrap()
350 .insert(name.clone(), new_type);
351 }
352 custom_types
353 };
354
355 let map = input_json
356 .as_object()
357 .ok_or(anyhow::anyhow!("Invalid json type"))?;
358 let mut types = IndexMap::new();
359 for (key, val) in map.iter() {
360 if let Some(val_str) = val.as_str() {
361 types.insert(
362 key.to_string(),
363 Self::from_str(val_str, custom_types.as_ref())?,
364 );
365 } else {
366 anyhow::bail!("Invalid value type");
367 }
368 }
369 Ok(Self::from_map(type_name, types))
370 }
371
372 pub fn from_map(type_name: &str, map: IndexMap<String, CliqueValueType>) -> Self {
373 Self::Custom(CustomType::new(type_name.to_string(), map))
374 }
375
376 pub fn as_map(&self) -> Option<&IndexMap<String, CliqueValueType>> {
377 match self {
378 Self::Custom(custom) => Some(&custom.type_),
379 _ => None,
380 }
381 }
382
383 #[cfg(feature = "with-syn")]
384 pub fn into_rust_syn(&self) -> Option<syn::Type> {
385 Some(match self {
386 CliqueValueType::Bool => syn::parse_quote! { bool },
387 CliqueValueType::String => syn::parse_quote! { String },
388 CliqueValueType::Bytes => syn::parse_quote! { Vec<u8> },
389 CliqueValueType::Address => syn::parse_quote! { ::clique_types::value::Address },
390 CliqueValueType::Float => syn::parse_quote! { f64 },
391 CliqueValueType::Int8 => syn::parse_quote! { i8 },
392 CliqueValueType::Int16 => syn::parse_quote! { i16 },
393 CliqueValueType::Int32 => syn::parse_quote! { i32 },
394 CliqueValueType::Int64 => syn::parse_quote! { i64 },
395 CliqueValueType::Int128 => syn::parse_quote! { i128 },
396 CliqueValueType::Int256 => syn::parse_quote! { ::clique_types::value::Int256 },
397 CliqueValueType::Uint8 => syn::parse_quote! { u8 },
398 CliqueValueType::Uint16 => syn::parse_quote! { u16 },
399 CliqueValueType::Uint32 => syn::parse_quote! { u32 },
400 CliqueValueType::Uint64 => syn::parse_quote! { u64 },
401 CliqueValueType::Uint128 => syn::parse_quote! { u128 },
402 CliqueValueType::Uint256 => syn::parse_quote! { ::clique_types::value::Uint256 },
403 CliqueValueType::Array(boxed_type) => boxed_type
404 .into_rust_syn()
405 .map(|item_type| syn::parse_quote! { Vec<#item_type> })?,
406 CliqueValueType::Custom(custom) => {
407 let ident = syn::Ident::new(&custom.name, proc_macro2::Span::call_site());
408 syn::parse_quote! { #ident }
409 }
410 })
411 }
412
413 pub fn to_bytes(&self) -> Result<Vec<u8>> {
415 Ok(bincode::serialize(self)?)
416 }
417
418 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
420 Ok(bincode::deserialize(bytes)?)
421 }
422}
423
424#[cfg(test)]
425mod test {
426 use super::*;
427
428 #[cfg(feature = "codec")]
429 #[test]
430 fn test_convert_json_to_clique_value_type() {
431 let type_name = "input";
432 let input_json = serde_json::json!({"url": "string", "strings": "string[]"});
433 let types_json = serde_json::json!({});
434 let clique_value_type =
435 CliqueValueType::from_json_object(type_name, input_json, types_json).unwrap();
436 println!("{:?}", clique_value_type);
437
438 let type_name = "input";
439 let input_json = serde_json::json!({"url": "string", "strings": "string[]"});
440 let types_json = serde_json::json!(null);
441 let clique_value_type =
442 CliqueValueType::from_json_object(type_name, input_json, types_json).unwrap();
443 println!("{:?}", clique_value_type);
444
445 let type_name = "input";
446 let input_json = serde_json::json!({"url": "string", "encoding": "Transformation[]"});
447 let types_json =
448 serde_json::json!({"Transformation": {"from": "string", "soltype": "string"}});
449 let clique_value_type =
450 CliqueValueType::from_json_object(type_name, input_json, types_json).unwrap();
451 println!("{:?}", clique_value_type);
452
453 let type_name = "input";
454 let input_json = serde_json::json!({"url": "string", "encoding": "Transformation[]"});
455 let types_json = serde_json::json!({"BaseCustomType": {"field": "string"},
456 "Transformation": {"from": "string", "bases": "BaseCustomType[]"}});
457 let clique_value_type =
458 CliqueValueType::from_json_object(type_name, input_json, types_json).unwrap();
459 println!("{:?}", clique_value_type);
460 }
461}