Skip to main content

ic_canister_kit/candid/
types.rs

1use std::collections::HashMap;
2
3use candid::CandidType;
4use serde::{Deserialize, Serialize};
5
6/// 有的名字作为 key 需要加双引号
7fn wrapped_key_word(name: &str) -> String {
8    if match name {
9        "bool" => true,
10        "nat" => true,
11        "int" => true,
12        "nat8" => true,
13        "nat16" => true,
14        "nat32" => true,
15        "nat64" => true,
16        "int8" => true,
17        "int16" => true,
18        "int32" => true,
19        "int64" => true,
20        "float32" => true,
21        "float64" => true,
22        "null" => true,
23        "text" => true,
24        "principal" => true,
25        "vec" => true,
26        "opt" => true,
27        "record" => true,
28        "variant" => true,
29        // "tuple" => true, // 不是关键字
30        "unknown" => true,
31        "empty" => true,
32        "reserved" => true,
33        "func" => true,
34        "service" => true,
35        "rec" => true, // 可能是关键字
36        _ => false,
37    } || name.contains(' ')
38        || name.contains('-')
39        || name.contains('\\')
40    {
41        format!("\"{}\"", name)
42    } else {
43        name.to_string()
44    }
45}
46
47/// 有可能有名称
48#[derive(Debug, Clone, CandidType, Serialize, Deserialize, Eq, PartialEq, Default)]
49pub struct WrappedCandidTypeName {
50    /// 有时候有名字
51    #[serde(rename = "name", skip_serializing_if = "Option::is_none")]
52    pub name: Option<String>,
53}
54
55impl WrappedCandidTypeName {
56    pub(super) fn from(name: Option<String>) -> Self {
57        Self { name }
58    }
59}
60
61/// 有可能有名称
62#[derive(Debug, Clone, CandidType, Serialize, Deserialize, Eq, PartialEq)]
63pub struct WrappedCandidTypeSubtype {
64    /// 子类型
65    #[serde(rename = "subtype")]
66    pub subtype: Box<WrappedCandidType>,
67
68    /// 有时候有名字
69    #[serde(rename = "name", skip_serializing_if = "Option::is_none")]
70    pub name: Option<String>,
71}
72
73/// 有可能有名称
74#[derive(Debug, Clone, CandidType, Serialize, Deserialize, Eq, PartialEq)]
75pub struct WrappedCandidTypeRecord {
76    /// 子类型
77    #[serde(rename = "subitems")]
78    pub subitems: Vec<(String, WrappedCandidType)>,
79
80    /// 有时候有名字
81    #[serde(rename = "name", skip_serializing_if = "Option::is_none")]
82    pub name: Option<String>,
83}
84
85impl WrappedCandidTypeRecord {
86    /// 文本
87    pub fn to_text(&self) -> String {
88        let Self { subitems, .. } = self;
89
90        if subitems.is_empty() {
91            return "record {}".to_string();
92        }
93
94        format!(
95            "record {{ {} }}",
96            subitems
97                .iter()
98                .map(|(name, subtype)| format!("{} : {}", wrapped_key_word(name), subtype.to_text()))
99                .collect::<Vec<_>>()
100                .join("; ")
101        )
102    }
103}
104
105/// 有可能有名称
106#[derive(Debug, Clone, CandidType, Serialize, Deserialize, Eq, PartialEq)]
107pub struct WrappedCandidTypeVariant {
108    /// 子类型
109    #[serde(rename = "subitems")]
110    pub subitems: Vec<(String, Option<WrappedCandidType>)>,
111
112    /// 有时候有名字
113    #[serde(rename = "name", skip_serializing_if = "Option::is_none")]
114    pub name: Option<String>,
115}
116
117impl WrappedCandidTypeVariant {
118    /// 文本
119    pub fn to_text(&self) -> String {
120        let Self { subitems, .. } = self;
121
122        if subitems.is_empty() {
123            return "variant {}".to_string();
124        }
125
126        format!(
127            "variant {{ {} }}",
128            subitems
129                .iter()
130                .map(|(name, subtype)| {
131                    if let Some(subtype) = subtype {
132                        format!("{} : {}", wrapped_key_word(name), subtype.to_text())
133                    } else {
134                        wrapped_key_word(name)
135                    }
136                })
137                .collect::<Vec<_>>()
138                .join("; ")
139        )
140    }
141}
142
143/// 有可能有名称
144#[derive(Debug, Clone, CandidType, Serialize, Deserialize, Eq, PartialEq)]
145pub struct WrappedCandidTypeTuple {
146    /// 子类型
147    #[serde(rename = "subitems")]
148    pub subitems: Vec<WrappedCandidType>,
149
150    /// 有时候有名字
151    #[serde(rename = "name", skip_serializing_if = "Option::is_none")]
152    pub name: Option<String>,
153}
154
155impl WrappedCandidTypeTuple {
156    /// 文本
157    pub fn to_text(&self) -> String {
158        let Self { subitems, .. } = self;
159
160        if subitems.is_empty() {
161            return "record {}".to_string();
162        }
163
164        format!(
165            "record {{ {} }}",
166            subitems
167                .iter()
168                .map(|subtype| subtype.to_text())
169                .collect::<Vec<_>>()
170                .join("; ")
171        )
172    }
173}
174
175/// 函数的注解 update 无注解
176#[derive(Debug, Copy, Clone, CandidType, Serialize, Deserialize, Eq, PartialEq)]
177pub enum FunctionAnnotation {
178    /// 查询函数, 可以用查询机制简化消耗的 cycles
179    #[serde(rename = "query")]
180    Query,
181    /// 复合查询函数
182    #[serde(rename = "composite_query")]
183    CompositeQuery,
184    /// 用于不关心返回值的函数, 触发即忘场景
185    #[serde(rename = "oneway")]
186    Oneway,
187}
188
189/// 函数结构体
190#[derive(Debug, Clone, CandidType, Serialize, Deserialize, Eq, PartialEq)]
191pub struct WrappedCandidTypeFunction {
192    /// args
193    #[serde(rename = "args", skip_serializing_if = "Vec::is_empty", default = "Vec::new")]
194    pub args: Vec<WrappedCandidType>,
195    /// results
196    #[serde(rename = "rets", skip_serializing_if = "Vec::is_empty", default = "Vec::new")]
197    pub rets: Vec<WrappedCandidType>,
198    /// annotation update query
199    #[serde(rename = "annotation", skip_serializing_if = "Option::is_none")]
200    pub annotation: Option<FunctionAnnotation>,
201
202    /// 有时候有名字
203    #[serde(rename = "name", skip_serializing_if = "Option::is_none")]
204    pub name: Option<String>,
205}
206
207impl WrappedCandidTypeFunction {
208    /// 文本
209    pub fn to_text(&self) -> String {
210        let Self {
211            args, rets, annotation, ..
212        } = self;
213
214        format!(
215            "func ({}) -> ({}){}",
216            args.iter().map(|t| t.to_text()).collect::<Vec<_>>().join(", "),
217            rets.iter().map(|t| t.to_text()).collect::<Vec<_>>().join(", "),
218            match annotation.as_ref() {
219                Some(annotation) => match annotation {
220                    FunctionAnnotation::Query => " query",
221                    FunctionAnnotation::CompositeQuery => " composite_query",
222                    FunctionAnnotation::Oneway => " oneway",
223                },
224                None => "",
225            }
226        )
227    }
228}
229
230/// service 结构体
231#[derive(Debug, Clone, CandidType, Serialize, Deserialize, Eq, PartialEq)]
232pub struct WrappedCandidTypeService {
233    /// args
234    #[serde(rename = "args", skip_serializing_if = "Vec::is_empty", default = "Vec::new")]
235    pub args: Vec<WrappedCandidType>,
236    /// methods
237    #[serde(rename = "methods", skip_serializing_if = "Vec::is_empty", default = "Vec::new")]
238    pub methods: Vec<(String, WrappedCandidTypeFunction)>,
239
240    /// 有时候有名字
241    #[serde(rename = "name", skip_serializing_if = "Option::is_none")]
242    pub name: Option<String>,
243}
244
245impl WrappedCandidTypeService {
246    /// 文本
247    pub fn to_text(&self) -> String {
248        let Self { args, methods, .. } = self;
249
250        format!(
251            "service :{} {{\n{}\n}}",
252            if args.is_empty() {
253                "".to_string()
254            } else {
255                format!(
256                    " ({}) ->",
257                    args.iter().map(|t| t.to_text()).collect::<Vec<_>>().join(", ")
258                )
259            },
260            if methods.is_empty() {
261                "".to_string()
262            } else {
263                format!(
264                    "\n{}\n",
265                    methods
266                        .iter()
267                        .map(|(name, func)| format!(
268                            "    {} : {};",
269                            wrapped_key_word(name),
270                            func.to_text().trim_start_matches("func ")
271                        ))
272                        .collect::<Vec<_>>()
273                        .join("\n")
274                )
275            }
276        )
277    }
278
279    /// 转化为方法
280    pub fn to_methods(&self) -> HashMap<String, String> {
281        self.methods
282            .iter()
283            .map(|(method, candid)| {
284                (method.to_string(), {
285                    let func = candid.to_text();
286                    if let Some(func) = func.strip_prefix("func ") {
287                        func.to_string()
288                    } else {
289                        func
290                    }
291                })
292            })
293            .collect()
294    }
295}
296
297/// 循环 结构体
298#[derive(Debug, Clone, CandidType, Serialize, Deserialize, Eq, PartialEq)]
299pub struct WrappedCandidTypeRecursion {
300    ///  type
301    #[serde(rename = "ty")]
302    pub ty: Box<WrappedCandidType>,
303    /// 分配的序号
304    #[serde(rename = "id")]
305    pub id: u32,
306
307    /// 有时候有名字
308    #[serde(rename = "name", skip_serializing_if = "Option::is_none")]
309    pub name: Option<String>,
310}
311
312impl WrappedCandidTypeRecursion {
313    /// 文本
314    pub fn to_text(&self) -> String {
315        let Self { ty, id, .. } = self;
316
317        format!("μrec_{}.{}", id, ty.to_text())
318    }
319}
320
321/// 循环 结构体
322#[derive(Debug, Clone, CandidType, Serialize, Deserialize, Eq, PartialEq)]
323pub struct WrappedCandidTypeReference {
324    /// 分配的序号
325    #[serde(rename = "id")]
326    pub id: u32,
327
328    /// 有时候有名字
329    #[serde(rename = "name", skip_serializing_if = "Option::is_none")]
330    pub name: Option<String>,
331}
332
333impl WrappedCandidTypeReference {
334    /// 文本
335    pub fn to_text(&self) -> String {
336        let Self { id, .. } = self;
337
338        format!("rec_{}", id,)
339    }
340}
341
342/// 自定义的包装 Candid 类型
343#[derive(Debug, Clone, CandidType, Serialize, Deserialize, Eq, PartialEq)]
344pub enum WrappedCandidType {
345    // 基本类型
346    /// bool
347    /// boolean type: true false Motoko Bool / Rust bool / JavaScript true false
348    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-bool
349    #[serde(rename = "bool")]
350    Bool(WrappedCandidTypeName),
351    /// nat
352    /// nature number: Motoko Nat / Rust candid:Nat or u128 / JavaScript BigInt(10000) or 10000n
353    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-nat
354    #[serde(rename = "nat")]
355    Nat(WrappedCandidTypeName),
356    /// int
357    /// integer number: Motoko Int / Rust candid::Int or i128 / JavaScript BigInt(-10000) or -10000n
358    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-int
359    #[serde(rename = "int")]
360    Int(WrappedCandidTypeName),
361    /// nat8
362    /// integer with limit bits
363    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-natn-and-intn
364    #[serde(rename = "nat8")]
365    Nat8(WrappedCandidTypeName),
366    /// nat16
367    /// integer with limit bits
368    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-natn-and-intn
369    #[serde(rename = "nat16")]
370    Nat16(WrappedCandidTypeName),
371    /// nat32
372    /// integer with limit bits
373    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-natn-and-intn
374    #[serde(rename = "nat32")]
375    Nat32(WrappedCandidTypeName),
376    /// nat64
377    /// integer with limit bits
378    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-natn-and-intn
379    #[serde(rename = "nat64")]
380    Nat64(WrappedCandidTypeName),
381    /// int8
382    /// integer with limit bits
383    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-natn-and-intn
384    #[serde(rename = "int8")]
385    Int8(WrappedCandidTypeName),
386    /// int16
387    /// integer with limit bits
388    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-natn-and-intn
389    #[serde(rename = "int16")]
390    Int16(WrappedCandidTypeName),
391    /// int32
392    /// integer with limit bits
393    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-natn-and-intn
394    #[serde(rename = "int32")]
395    Int32(WrappedCandidTypeName),
396    /// int64
397    /// integer with limit bits
398    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-natn-and-intn
399    #[serde(rename = "int64")]
400    Int64(WrappedCandidTypeName),
401    /// float32
402    /// float number: Motoko Float is 64 bits / Rust f32 f64 / JavaScript float
403    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-float32-and-float64
404    #[serde(rename = "float32")]
405    Float32(WrappedCandidTypeName),
406    /// float64
407    /// float number: Motoko Float is 64 bits / Rust f32 f64 / JavaScript float
408    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-float32-and-float64
409    #[serde(rename = "float64")]
410    Float64(WrappedCandidTypeName),
411    /// null
412    /// null type: only value is null Motoko Null / Rust None / JavaScript null
413    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-null
414    #[serde(rename = "null")]
415    Null(WrappedCandidTypeName),
416    /// text
417    /// text type: Motoko Text / Rust String or &str / JavaScript string
418    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-text
419    #[serde(rename = "text")]
420    Text(WrappedCandidTypeName),
421    /// principal
422    /// principal type: like "zwigo-aiaaa-aaaaa-qaa3a-cai" Motoko Principal / candid::Principal / JavaScript Principal.fromText("aaaaa-aa")
423    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-principal
424    #[serde(rename = "principal")]
425    Principal(WrappedCandidTypeName),
426    // Blob, // 一律以 vec nat8 替代
427    // 子类型
428    /// vec T
429    /// binary data: vec nat8 Motoko Blob / Rust Vec<u8> or &[u8] / JavaScript [1, 2, 3]
430    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-blob
431    /// array of some type: vec {1,3} Motoko [T] / Rust Vec<T> &[T] / JavaScript Array
432    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-vec-t
433    #[serde(rename = "vec")]
434    Vec(WrappedCandidTypeSubtype),
435    /// opt T
436    /// option type: null opt t Motoko ?T / Rust Option<T> / [] [t]
437    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-opt-t
438    #[serde(rename = "opt")]
439    Opt(WrappedCandidTypeSubtype),
440    // 多个子类型
441    /// record { .. } // name=T
442    /// object type: record { name="123"; } Motoko record { name: "123" } / Rust struct / JavaScript object
443    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-record--n--t--
444    #[serde(rename = "record")]
445    Record(WrappedCandidTypeRecord),
446    /// variant { .. }
447    /// enumerate type: variant { ok : nat; error : text } / Rust enum / JavaScript { dot: null }
448    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-variant--n--t--
449    #[serde(rename = "variant")]
450    Variant(WrappedCandidTypeVariant),
451    /// tuple record { .. } // T
452    /// tuple type: subitem has no name
453    /// JavaScript array value
454    #[serde(rename = "tuple")]
455    Tuple(WrappedCandidTypeTuple),
456    // 特殊类型
457    /// unknown
458    /// unknown type
459    #[serde(rename = "unknown")]
460    Unknown(WrappedCandidTypeName),
461    /// empty
462    /// empty type
463    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-empty
464    #[serde(rename = "empty")]
465    Empty(WrappedCandidTypeName), // 没有值的类型, 是其他类型的子类型
466    /// reserved
467    /// reserved type: some function arguments can be ignore
468    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-reserved
469    #[serde(rename = "reserved")]
470    Reserved(WrappedCandidTypeName), // 占位不使用的类型
471    /// func
472    /// func type
473    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-func---
474    #[serde(rename = "func")]
475    Func(WrappedCandidTypeFunction),
476    /// service
477    /// service type: canister's api
478    /// https://internetcomputer.org/docs/current/references/candid-ref/#type-service-
479    #[serde(rename = "service")]
480    Service(WrappedCandidTypeService),
481    /// rec
482    /// object type: some subtype or subitem is recursion
483    #[serde(rename = "rec")]
484    Rec(WrappedCandidTypeRecursion), // 循环类型中的主类型
485    /// ref
486    #[serde(rename = "ref")]
487    Reference(WrappedCandidTypeReference), // 循环类型中的引用类型
488}
489
490impl WrappedCandidType {
491    /// 文本
492    pub fn to_text(&self) -> String {
493        match self {
494            Self::Bool(_) => String::from("bool"),
495            Self::Nat(_) => String::from("nat"),
496            Self::Int(_) => String::from("int"),
497            Self::Nat8(_) => String::from("nat8"),
498            Self::Nat16(_) => String::from("nat16"),
499            Self::Nat32(_) => String::from("nat32"),
500            Self::Nat64(_) => String::from("nat64"),
501            Self::Int8(_) => String::from("int8"),
502            Self::Int16(_) => String::from("int16"),
503            Self::Int32(_) => String::from("int32"),
504            Self::Int64(_) => String::from("int64"),
505            Self::Float32(_) => String::from("float32"),
506            Self::Float64(_) => String::from("float64"),
507            Self::Null(_) => String::from("null"),
508            Self::Text(_) => String::from("text"),
509            Self::Principal(_) => String::from("principal"),
510            Self::Vec(WrappedCandidTypeSubtype { subtype, .. }) => {
511                format!("vec {}", subtype.to_text())
512            }
513            Self::Opt(WrappedCandidTypeSubtype { subtype, .. }) => {
514                format!("opt {}", subtype.to_text())
515            }
516            Self::Record(record) => record.to_text(),
517            Self::Variant(variant) => variant.to_text(),
518            Self::Tuple(tuple) => tuple.to_text(),
519            Self::Unknown(_) => String::from("unknown"),
520            Self::Empty(_) => String::from("empty"),
521            Self::Reserved(_) => String::from("reserved"),
522            Self::Func(func) => func.to_text(),
523            Self::Service(service) => service.to_text(),
524            Self::Rec(recursion) => recursion.to_text(),
525            Self::Reference(reference) => reference.to_text(),
526        }
527    }
528}