clique_types/value/
mod.rs

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    /// Serialize the struct
180    pub fn to_bytes(&self) -> Result<Vec<u8>> {
181        Ok(bincode::serialize(self)?)
182    }
183
184    /// Deserialize the struct
185    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    /// For example, the parms for clique_httpsRequest task would be:
322    /// type_name: "input"
323    /// input_json: {"url": "string", "encoding": "Transformation[]"}
324    /// types_json: {"Transformation": {"from": "string", "soltype": "string"}}
325    ///
326    /// If there is no custom type, just use empty json object or null as types_json.
327    /// And if the custom types of the task are nested, the types_json could be:
328    /// types_json: {"BaseCustomType": {"field": "string"},
329    ///              "Transformation": {"from": "string", "bases": "BaseCustomType[]"}}
330    #[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    /// Serialize the struct
414    pub fn to_bytes(&self) -> Result<Vec<u8>> {
415        Ok(bincode::serialize(self)?)
416    }
417
418    /// Deserialize the struct
419    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}