From a1fe5dfcff10af4858df4f9242f2192a3ea03bcc Mon Sep 17 00:00:00 2001 From: Yan Chen Date: Sun, 20 Aug 2023 18:04:52 -0700 Subject: [PATCH 1/7] use pascal case for type names --- Cargo.lock | 10 + rust/candid/Cargo.toml | 3 +- rust/candid/src/bindings/rust.rs | 62 +++-- rust/candid/tests/assets/ok/actor.rs | 12 +- rust/candid/tests/assets/ok/comment.rs | 2 +- rust/candid/tests/assets/ok/escape.rs | 4 +- rust/candid/tests/assets/ok/example.rs | 56 ++-- rust/candid/tests/assets/ok/fieldnat.rs | 28 +- rust/candid/tests/assets/ok/keyword.rs | 52 ++-- rust/candid/tests/assets/ok/management.rs | 256 ++++++++++-------- rust/candid/tests/assets/ok/recursion.rs | 30 +- .../candid/tests/assets/ok/recursive_class.rs | 4 +- rust/candid/tests/assets/ok/service.rs | 9 +- 13 files changed, 296 insertions(+), 232 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 937f3f2d..c0dc09d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -267,6 +267,7 @@ dependencies = [ "byteorder", "candid_derive", "codespan-reporting", + "convert_case", "crc32fast", "criterion", "data-encoding", @@ -441,6 +442,15 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cpufeatures" version = "0.2.9" diff --git a/rust/candid/Cargo.toml b/rust/candid/Cargo.toml index df9887a7..4c1afa67 100644 --- a/rust/candid/Cargo.toml +++ b/rust/candid/Cargo.toml @@ -40,6 +40,7 @@ binread = { version = "2.1", features = ["debug_template"] } lalrpop-util = { version = "0.20.0", optional = true } logos = { version = "0.13", optional = true } +convert_case = { version = "0.6", optional = true } arbitrary = { version = "1.0", optional = true } # Don't upgrade serde_dhall. It will introduce dependency with invalid license. @@ -86,7 +87,7 @@ required-features = ["parser"] [features] configs = ["serde_dhall"] random = ["parser", "configs", "arbitrary", "fake", "rand"] -parser = ["lalrpop", "lalrpop-util", "logos"] +parser = ["lalrpop", "lalrpop-util", "logos", "convert_case"] all = ["random"] mute_warnings = [] arc_type = [] diff --git a/rust/candid/src/bindings/rust.rs b/rust/candid/src/bindings/rust.rs index 328aee26..9d075a2d 100644 --- a/rust/candid/src/bindings/rust.rs +++ b/rust/candid/src/bindings/rust.rs @@ -1,6 +1,7 @@ use super::analysis::{chase_actor, infer_rec}; use crate::pretty::*; use crate::types::{Field, Function, Label, SharedLabel, Type, TypeEnv, TypeInner}; +use convert_case::{Case, Casing}; use pretty::RcDoc; use std::collections::BTreeSet; @@ -56,25 +57,32 @@ static KEYWORDS: [&str; 51] = [ "while", "async", "await", "dyn", "abstract", "become", "box", "do", "final", "macro", "override", "priv", "typeof", "unsized", "virtual", "yield", "try", ]; -fn ident_(id: &str) -> (RcDoc, bool) { +fn ident_(id: &str, case: Option) -> (RcDoc, bool) { if id.is_empty() || id.starts_with(|c: char| !c.is_ascii_alphabetic() && c != '_') || id.chars().any(|c| !c.is_ascii_alphanumeric() && c != '_') { - (RcDoc::as_string(format!("_{}_", crate::idl_hash(id))), true) - } else if ["crate", "self", "super", "Self"].contains(&id) { - (str(id).append("_"), true) - } else if KEYWORDS.contains(&id) { - (str("r#").append(id), false) + return (RcDoc::text(format!("_{}_", crate::idl_hash(&id))), true); + } + let (is_rename, id) = if let Some(case) = case { + let new_id = id.to_case(case); + (new_id != id, new_id) + } else { + (false, id.to_owned()) + }; + if ["crate", "self", "super", "Self", "Result"].contains(&id.as_str()) { + (RcDoc::text(format!("{id}_")), true) + } else if KEYWORDS.contains(&id.as_str()) { + (RcDoc::text(format!("r#{id}")), is_rename) } else { - (str(id), false) + (RcDoc::text(id), is_rename) } } -fn ident(id: &str) -> RcDoc { - ident_(id).0 +fn ident(id: &str, case: Option) -> RcDoc { + ident_(id, case).0 } -fn field_name(id: &str) -> RcDoc { - let (doc, is_rename) = ident_(id); +fn field_name(id: &str, case: Option) -> RcDoc { + let (doc, is_rename) = ident_(id, case); if is_rename { str("#[serde(rename=\"") .append(id.escape_debug().to_string()) @@ -107,7 +115,7 @@ fn pp_ty<'a>(ty: &'a Type, recs: &RecPoints) -> RcDoc<'a> { Reserved => str("candid::Reserved"), Empty => str("candid::Empty"), Var(ref id) => { - let name = ident(id); + let name = ident(id, Some(Case::Pascal)); if recs.contains(id.as_str()) { str("Box<").append(name).append(">") } else { @@ -128,15 +136,15 @@ fn pp_ty<'a>(ty: &'a Type, recs: &RecPoints) -> RcDoc<'a> { } } -fn pp_label(id: &SharedLabel) -> RcDoc { +fn pp_label(id: &SharedLabel, is_variant: bool) -> RcDoc { match &**id { - Label::Named(str) => field_name(str), + Label::Named(str) => field_name(str, if is_variant { Some(Case::Pascal) } else { None }), Label::Id(n) | Label::Unnamed(n) => str("_").append(RcDoc::as_string(n)).append("_"), } } fn pp_record_field<'a>(field: &'a Field, recs: &RecPoints) -> RcDoc<'a> { - pp_label(&field.id) + pp_label(&field.id, false) .append(kwd(":")) .append(pp_ty(&field.ty, recs)) } @@ -153,9 +161,9 @@ fn pp_record_fields<'a>(fs: &'a [Field], recs: &RecPoints) -> RcDoc<'a> { fn pp_variant_field<'a>(field: &'a Field, recs: &RecPoints) -> RcDoc<'a> { match field.ty.as_ref() { - TypeInner::Null => pp_label(&field.id), - TypeInner::Record(fs) => pp_label(&field.id).append(pp_record_fields(fs, recs)), - _ => pp_label(&field.id).append(enclose("(", pp_ty(&field.ty, recs), ")")), + TypeInner::Null => pp_label(&field.id, true), + TypeInner::Record(fs) => pp_label(&field.id, true).append(pp_record_fields(fs, recs)), + _ => pp_label(&field.id, true).append(enclose("(", pp_ty(&field.ty, recs), ")")), } } @@ -177,7 +185,7 @@ fn pp_defs<'a>( }; lines(def_list.iter().map(|id| { let ty = env.find_type(id).unwrap(); - let name = ident(id).append(" "); + let name = ident(id, Some(Case::Pascal)).append(" "); let vis = "pub "; match ty.as_ref() { TypeInner::Record(fs) => { @@ -220,7 +228,7 @@ fn pp_defs<'a>( .append(RcDoc::line()) .append(vis) .append("struct ") - .append(ident(id)) + .append(ident(id, Some(Case::Pascal))) .append(enclose("(", pp_ty(ty, recs), ")")) .append(";") .append(RcDoc::hardline()) @@ -270,7 +278,7 @@ fn pp_ty_service(serv: &[(String, Type)]) -> RcDoc { } fn pp_function<'a>(config: &Config, id: &'a str, func: &'a Function) -> RcDoc<'a> { - let name = ident(id); + let name = ident(id, None); let empty = BTreeSet::new(); let arg_prefix = str(match config.target { Target::CanisterCall => "&self", @@ -430,7 +438,7 @@ fn path_to_var(path: &[TypePath]) -> String { TypePath::Init => "init", }) .collect(); - name.join("_") + name.join("_").to_case(Case::Pascal) } // Convert structural typing to nominal typing to fit Rust's type system fn nominalize(env: &mut TypeEnv, path: &mut Vec, t: &Type) -> Type { @@ -508,6 +516,11 @@ fn nominalize(env: &mut TypeEnv, path: &mut Vec, t: &Type) -> Type { .into_iter() .enumerate() .map(|(i, ty)| { + let i = if i == 0 { + "".to_string() + } else { + i.to_string() + }; path.push(TypePath::Func(format!("arg{i}"))); let ty = nominalize(env, path, &ty); path.pop(); @@ -519,6 +532,11 @@ fn nominalize(env: &mut TypeEnv, path: &mut Vec, t: &Type) -> Type { .into_iter() .enumerate() .map(|(i, ty)| { + let i = if i == 0 { + "".to_string() + } else { + i.to_string() + }; path.push(TypePath::Func(format!("ret{i}"))); let ty = nominalize(env, path, &ty); path.pop(); diff --git a/rust/candid/tests/assets/ok/actor.rs b/rust/candid/tests/assets/ok/actor.rs index 8bdb8b28..47f70fa4 100644 --- a/rust/candid/tests/assets/ok/actor.rs +++ b/rust/candid/tests/assets/ok/actor.rs @@ -3,15 +3,15 @@ use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; -candid::define_function!(pub f : (i8) -> (i8)); -candid::define_function!(pub h : (f) -> (f)); -pub type g = f; +candid::define_function!(pub F : (i8) -> (i8)); +candid::define_function!(pub H : (F) -> (F)); +pub type G = F; #[derive(CandidType, Deserialize)] -pub struct o(Option>); +pub struct O(Option>); pub struct SERVICE(pub Principal); impl SERVICE { - pub async fn f(&self, arg0: candid::Nat) -> Result<(h,)> { + pub async fn f(&self, arg0: candid::Nat) -> Result<(H,)> { ic_cdk::call(self.0, "f", (arg0,)).await } pub async fn g(&self, arg0: i8) -> Result<(i8,)> { @@ -20,7 +20,7 @@ impl SERVICE { pub async fn h(&self, arg0: i8) -> Result<(i8,)> { ic_cdk::call(self.0, "h", (arg0,)).await } - pub async fn o(&self, arg0: o) -> Result<(o,)> { + pub async fn o(&self, arg0: O) -> Result<(O,)> { ic_cdk::call(self.0, "o", (arg0,)).await } } diff --git a/rust/candid/tests/assets/ok/comment.rs b/rust/candid/tests/assets/ok/comment.rs index d5cd1448..36a16f68 100644 --- a/rust/candid/tests/assets/ok/comment.rs +++ b/rust/candid/tests/assets/ok/comment.rs @@ -3,5 +3,5 @@ use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; -pub type id = u8; +pub type Id = u8; diff --git a/rust/candid/tests/assets/ok/escape.rs b/rust/candid/tests/assets/ok/escape.rs index aa4ca474..1dfbb98c 100644 --- a/rust/candid/tests/assets/ok/escape.rs +++ b/rust/candid/tests/assets/ok/escape.rs @@ -4,7 +4,7 @@ use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] -pub struct t { +pub struct T { #[serde(rename="\"")] _34_: candid::Nat, #[serde(rename="\'")] @@ -17,7 +17,7 @@ pub struct t { pub struct SERVICE(pub Principal); impl SERVICE { - pub async fn _2635468193_(&self, arg0: t) -> Result<()> { + pub async fn _2635468193_(&self, arg0: T) -> Result<()> { ic_cdk::call(self.0, "\n\'\"\'\'\"\"\r\t", (arg0,)).await } } diff --git a/rust/candid/tests/assets/ok/example.rs b/rust/candid/tests/assets/ok/example.rs index 7b65ee05..5eccfa9d 100644 --- a/rust/candid/tests/assets/ok/example.rs +++ b/rust/candid/tests/assets/ok/example.rs @@ -4,86 +4,86 @@ use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] -pub struct node { head: candid::Nat, tail: Box } +pub struct Node { head: candid::Nat, tail: Box } #[derive(CandidType, Deserialize)] -pub struct list(Option); +pub struct List(Option); -pub type my_type = Principal; +pub type MyType = Principal; #[derive(CandidType, Deserialize)] -pub struct List_inner { head: candid::Int, tail: Box } +pub struct ListInner { head: candid::Int, tail: Box } #[derive(CandidType, Deserialize)] -pub struct List(Option); +pub struct List(Option); #[derive(CandidType, Deserialize)] -pub struct nested_3 { _0_: candid::Nat, _42_: candid::Nat, _43_: u8 } +pub struct Nested3 { _0_: candid::Nat, _42_: candid::Nat, _43_: u8 } #[derive(CandidType, Deserialize)] -pub enum nested_41 { _42_, A, B, C } +pub enum Nested41 { _42_, A, B, C } #[derive(CandidType, Deserialize)] -pub struct nested { +pub struct Nested { _0_: candid::Nat, _1_: candid::Nat, _2_: (candid::Nat,candid::Int,), - _3_: nested_3, + _3_: Nested3, _40_: candid::Nat, - _41_: nested_41, + _41_: Nested41, _42_: candid::Nat, } -candid::define_service!(pub broker_find_ret0 : { +candid::define_service!(pub BrokerFindRet : { "current" : candid::func!(() -> (u32)); "up" : candid::func!(() -> ()); }); -candid::define_service!(pub broker : { - "find" : candid::func!((String) -> (broker_find_ret0)); +candid::define_service!(pub Broker : { + "find" : candid::func!((String) -> (BrokerFindRet)); }); #[derive(CandidType, Deserialize)] -pub enum h_arg1 { A(candid::Nat), B(Option) } +pub enum HArg1 { A(candid::Nat), B(Option) } #[derive(CandidType, Deserialize)] -pub struct h_ret0_42 {} +pub struct HRet42 {} #[derive(CandidType, Deserialize)] -pub struct h_ret0 { _42_: h_ret0_42, id: candid::Nat } +pub struct HRet { _42_: HRet42, id: candid::Nat } -candid::define_function!(pub f_arg1 : (i32) -> (i64)); -candid::define_function!(pub f : (List, f_arg1) -> (Option)); +candid::define_function!(pub FArg1 : (i32) -> (i64)); +candid::define_function!(pub F : (List, FArg1) -> (Option)); #[derive(CandidType, Deserialize)] -pub struct b (candid::Int,candid::Nat,); +pub struct B (candid::Int,candid::Nat,); #[derive(CandidType, Deserialize)] -pub enum a { a, b(b) } +pub enum A { #[serde(rename="a")] A, #[serde(rename="b")] B(B) } pub struct SERVICE(pub Principal); impl SERVICE { pub async fn f( &self, - arg0: list, + arg0: List, arg1: serde_bytes::ByteBuf, arg2: Option, ) -> Result<()> { ic_cdk::call(self.0, "f", (arg0,arg1,arg2,)).await } pub async fn g( &self, - arg0: my_type, + arg0: MyType, arg1: List, arg2: Option, - arg3: nested, - ) -> Result<(candid::Int,broker,)> { + arg3: Nested, + ) -> Result<(candid::Int,Broker,)> { ic_cdk::call(self.0, "g", (arg0,arg1,arg2,arg3,)).await } pub async fn h( &self, arg0: Vec>, - arg1: h_arg1, + arg1: HArg1, arg2: Option, - ) -> Result<(h_ret0,)> { ic_cdk::call(self.0, "h", (arg0,arg1,arg2,)).await } - pub async fn i(&self, arg0: List, arg1: f_arg1) -> Result<(Option,)> { + ) -> Result<(HRet,)> { ic_cdk::call(self.0, "h", (arg0,arg1,arg2,)).await } + pub async fn i(&self, arg0: List, arg1: FArg1) -> Result<(Option,)> { ic_cdk::call(self.0, "i", (arg0,arg1,)).await } - pub async fn x(&self, arg0: a, arg1: b) -> Result<(Option,Option,)> { + pub async fn x(&self, arg0: A, arg1: B) -> Result<(Option,Option,)> { ic_cdk::call(self.0, "x", (arg0,arg1,)).await } } diff --git a/rust/candid/tests/assets/ok/fieldnat.rs b/rust/candid/tests/assets/ok/fieldnat.rs index b3e973aa..d79cde40 100644 --- a/rust/candid/tests/assets/ok/fieldnat.rs +++ b/rust/candid/tests/assets/ok/fieldnat.rs @@ -4,53 +4,53 @@ use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] -pub struct bar_arg0 { #[serde(rename="2")] _50_: candid::Int } +pub struct BarArg { #[serde(rename="2")] _50_: candid::Int } #[derive(CandidType, Deserialize)] -pub enum bar_ret0 { e20, e30 } +pub enum BarRet { #[serde(rename="e20")] E20, #[serde(rename="e30")] E30 } #[derive(CandidType, Deserialize)] -pub struct baz_arg0 { _2_: candid::Int, #[serde(rename="2")] _50_: candid::Nat } +pub struct BazArg { _2_: candid::Int, #[serde(rename="2")] _50_: candid::Nat } #[derive(CandidType, Deserialize)] -pub struct baz_ret0 {} +pub struct BazRet {} #[derive(CandidType, Deserialize)] -pub struct tuple (String,String,); +pub struct Tuple (String,String,); #[derive(CandidType, Deserialize)] -pub struct non_tuple { _1_: String, _2_: String } +pub struct NonTuple { _1_: String, _2_: String } #[derive(CandidType, Deserialize)] -pub enum bib_ret0 { _0_(candid::Int) } +pub enum BibRet { _0_(candid::Int) } #[derive(CandidType, Deserialize)] -pub struct foo_arg0 { _2_: candid::Int } +pub struct FooArg { _2_: candid::Int } #[derive(CandidType, Deserialize)] -pub struct foo_ret0 { _2_: candid::Int, _2: candid::Int } +pub struct FooRet { _2_: candid::Int, _2: candid::Int } pub struct SERVICE(pub Principal); impl SERVICE { pub async fn bab(&self, arg0: candid::Int, arg1: candid::Nat) -> Result<()> { ic_cdk::call(self.0, "bab", (arg0,arg1,)).await } - pub async fn bar(&self, arg0: bar_arg0) -> Result<(bar_ret0,)> { + pub async fn bar(&self, arg0: BarArg) -> Result<(BarRet,)> { ic_cdk::call(self.0, "bar", (arg0,)).await } pub async fn bas(&self, arg0: (candid::Int,candid::Int,)) -> Result< ((String,candid::Nat,),) > { ic_cdk::call(self.0, "bas", (arg0,)).await } - pub async fn baz(&self, arg0: baz_arg0) -> Result<(baz_ret0,)> { + pub async fn baz(&self, arg0: BazArg) -> Result<(BazRet,)> { ic_cdk::call(self.0, "baz", (arg0,)).await } - pub async fn bba(&self, arg0: tuple) -> Result<(non_tuple,)> { + pub async fn bba(&self, arg0: Tuple) -> Result<(NonTuple,)> { ic_cdk::call(self.0, "bba", (arg0,)).await } - pub async fn bib(&self, arg0: (candid::Int,)) -> Result<(bib_ret0,)> { + pub async fn bib(&self, arg0: (candid::Int,)) -> Result<(BibRet,)> { ic_cdk::call(self.0, "bib", (arg0,)).await } - pub async fn foo(&self, arg0: foo_arg0) -> Result<(foo_ret0,)> { + pub async fn foo(&self, arg0: FooArg) -> Result<(FooRet,)> { ic_cdk::call(self.0, "foo", (arg0,)).await } } diff --git a/rust/candid/tests/assets/ok/keyword.rs b/rust/candid/tests/assets/ok/keyword.rs index f61a15ca..f4f36051 100644 --- a/rust/candid/tests/assets/ok/keyword.rs +++ b/rust/candid/tests/assets/ok/keyword.rs @@ -4,62 +4,64 @@ use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] -pub struct o(Option>); +pub struct O(Option>); #[derive(CandidType, Deserialize)] -pub struct field_arg0 { test: u16, _1291438163_: u8 } +pub struct FieldArg { test: u16, _1291438163_: u8 } #[derive(CandidType, Deserialize)] -pub struct field_ret0 {} +pub struct FieldRet {} #[derive(CandidType, Deserialize)] -pub struct fieldnat_arg0 { +pub struct FieldnatArg { _2_: candid::Int, #[serde(rename="2")] _50_: candid::Nat, } #[derive(CandidType, Deserialize)] -pub struct node { head: candid::Nat, tail: Box } +pub struct Node { head: candid::Nat, tail: Box } #[derive(CandidType, Deserialize)] -pub struct list(Option); +pub struct List(Option); #[derive(CandidType, Deserialize)] -pub enum r#if { - branch{ val: candid::Int, left: Box, right: Box }, - leaf(candid::Int), +pub enum If { + #[serde(rename="branch")] + Branch{ val: candid::Int, left: Box, right: Box }, + #[serde(rename="leaf")] + Leaf(candid::Int), } -candid::define_function!(pub stream_inner_next : () -> (stream) query); +candid::define_function!(pub StreamInnerNext : () -> (Stream) query); #[derive(CandidType, Deserialize)] -pub struct stream_inner { head: candid::Nat, next: stream_inner_next } +pub struct StreamInner { head: candid::Nat, next: StreamInnerNext } #[derive(CandidType, Deserialize)] -pub struct stream(Option); +pub struct Stream(Option); -candid::define_service!(pub r#return : { - "f" : t::ty(); - "g" : candid::func!((list) -> (r#if, stream)); +candid::define_service!(pub Return : { + "f" : T::ty(); + "g" : candid::func!((List) -> (If, Stream)); }); -candid::define_function!(pub t : (r#return) -> ()); +candid::define_function!(pub T : (Return) -> ()); #[derive(CandidType, Deserialize)] -pub enum variant_arg0 { A, B, C, D(f64) } +pub enum VariantArg { A, B, C, D(f64) } pub struct SERVICE(pub Principal); impl SERVICE { pub async fn Oneway(&self) -> Result<()> { ic_cdk::call(self.0, "Oneway", ()).await } - pub async fn f_(&self, arg0: o) -> Result<(o,)> { + pub async fn f_(&self, arg0: O) -> Result<(O,)> { ic_cdk::call(self.0, "f_", (arg0,)).await } - pub async fn field(&self, arg0: field_arg0) -> Result<(field_ret0,)> { + pub async fn field(&self, arg0: FieldArg) -> Result<(FieldRet,)> { ic_cdk::call(self.0, "field", (arg0,)).await } - pub async fn fieldnat(&self, arg0: fieldnat_arg0) -> Result< - ((candid::Int,),) - > { ic_cdk::call(self.0, "fieldnat", (arg0,)).await } + pub async fn fieldnat(&self, arg0: FieldnatArg) -> Result<((candid::Int,),)> { + ic_cdk::call(self.0, "fieldnat", (arg0,)).await + } pub async fn oneway(&self, arg0: u8) -> Result<()> { ic_cdk::call(self.0, "oneway", (arg0,)).await } @@ -69,10 +71,10 @@ impl SERVICE { pub async fn query(&self, arg0: serde_bytes::ByteBuf) -> Result< (serde_bytes::ByteBuf,) > { ic_cdk::call(self.0, "query", (arg0,)).await } - pub async fn r#return(&self, arg0: o) -> Result<(o,)> { + pub async fn r#return(&self, arg0: O) -> Result<(O,)> { ic_cdk::call(self.0, "return", (arg0,)).await } - pub async fn service(&self, arg0: r#return) -> Result<()> { + pub async fn service(&self, arg0: Return) -> Result<()> { ic_cdk::call(self.0, "service", (arg0,)).await } pub async fn tuple( @@ -81,7 +83,7 @@ impl SERVICE { ) -> Result<((candid::Int,u8,),)> { ic_cdk::call(self.0, "tuple", (arg0,)).await } - pub async fn variant(&self, arg0: variant_arg0) -> Result<()> { + pub async fn variant(&self, arg0: VariantArg) -> Result<()> { ic_cdk::call(self.0, "variant", (arg0,)).await } } diff --git a/rust/candid/tests/assets/ok/management.rs b/rust/candid/tests/assets/ok/management.rs index c927f102..ef2f1338 100644 --- a/rust/candid/tests/assets/ok/management.rs +++ b/rust/candid/tests/assets/ok/management.rs @@ -3,64 +3,78 @@ use candid::{self, CandidType, Deserialize, Principal}; type Result = std::result::Result; #[derive(CandidType, Deserialize)] -pub enum bitcoin_network { mainnet, testnet } +pub enum BitcoinNetwork { + #[serde(rename="mainnet")] + Mainnet, + #[serde(rename="testnet")] + Testnet, +} -pub type bitcoin_address = String; +pub type BitcoinAddress = String; #[derive(CandidType, Deserialize)] -pub struct get_balance_request { - network: bitcoin_network, - address: bitcoin_address, +pub struct GetBalanceRequest { + network: BitcoinNetwork, + address: BitcoinAddress, min_confirmations: Option, } -pub type satoshi = u64; +pub type Satoshi = u64; #[derive(CandidType, Deserialize)] -pub struct get_current_fee_percentiles_request { network: bitcoin_network } +pub struct GetCurrentFeePercentilesRequest { network: BitcoinNetwork } -pub type millisatoshi_per_byte = u64; +pub type MillisatoshiPerByte = u64; #[derive(CandidType, Deserialize)] -pub enum get_utxos_request_filter_inner { - page(serde_bytes::ByteBuf), - min_confirmations(u32), +pub enum GetUtxosRequestFilterInner { + #[serde(rename="page")] + Page(serde_bytes::ByteBuf), + #[serde(rename="min_confirmations")] + MinConfirmations(u32), } #[derive(CandidType, Deserialize)] -pub struct get_utxos_request { - network: bitcoin_network, - filter: Option, - address: bitcoin_address, +pub struct GetUtxosRequest { + network: BitcoinNetwork, + filter: Option, + address: BitcoinAddress, } -pub type block_hash = serde_bytes::ByteBuf; +pub type BlockHash = serde_bytes::ByteBuf; #[derive(CandidType, Deserialize)] -pub struct outpoint { txid: serde_bytes::ByteBuf, vout: u32 } +pub struct Outpoint { txid: serde_bytes::ByteBuf, vout: u32 } #[derive(CandidType, Deserialize)] -pub struct utxo { height: u32, value: satoshi, outpoint: outpoint } +pub struct Utxo { height: u32, value: Satoshi, outpoint: Outpoint } #[derive(CandidType, Deserialize)] -pub struct get_utxos_response { +pub struct GetUtxosResponse { next_page: Option, tip_height: u32, - tip_block_hash: block_hash, - utxos: Vec, + tip_block_hash: BlockHash, + utxos: Vec, } #[derive(CandidType, Deserialize)] -pub struct send_transaction_request { +pub struct SendTransactionRequest { transaction: serde_bytes::ByteBuf, - network: bitcoin_network, + network: BitcoinNetwork, } -pub type canister_id = Principal; +pub type CanisterId = Principal; #[derive(CandidType, Deserialize)] -pub struct canister_status_arg0 { canister_id: canister_id } +pub struct CanisterStatusArg { canister_id: CanisterId } #[derive(CandidType, Deserialize)] -pub enum canister_status_ret0_status { stopped, stopping, running } +pub enum CanisterStatusRetStatus { + #[serde(rename="stopped")] + Stopped, + #[serde(rename="stopping")] + Stopping, + #[serde(rename="running")] + Running, +} #[derive(CandidType, Deserialize)] -pub struct definite_canister_settings { +pub struct DefiniteCanisterSettings { freezing_threshold: candid::Nat, controllers: Vec, memory_allocation: candid::Nat, @@ -68,17 +82,17 @@ pub struct definite_canister_settings { } #[derive(CandidType, Deserialize)] -pub struct canister_status_ret0 { - status: canister_status_ret0_status, +pub struct CanisterStatusRet { + status: CanisterStatusRetStatus, memory_size: candid::Nat, cycles: candid::Nat, - settings: definite_canister_settings, + settings: DefiniteCanisterSettings, idle_cycles_burned_per_day: candid::Nat, module_hash: Option, } #[derive(CandidType, Deserialize)] -pub struct canister_settings { +pub struct CanisterSettings { freezing_threshold: Option, controllers: Option>, memory_allocation: Option, @@ -86,161 +100,173 @@ pub struct canister_settings { } #[derive(CandidType, Deserialize)] -pub struct create_canister_arg0 { settings: Option } +pub struct CreateCanisterArg { settings: Option } #[derive(CandidType, Deserialize)] -pub struct create_canister_ret0 { canister_id: canister_id } +pub struct CreateCanisterRet { canister_id: CanisterId } #[derive(CandidType, Deserialize)] -pub struct delete_canister_arg0 { canister_id: canister_id } +pub struct DeleteCanisterArg { canister_id: CanisterId } #[derive(CandidType, Deserialize)] -pub struct deposit_cycles_arg0 { canister_id: canister_id } +pub struct DepositCyclesArg { canister_id: CanisterId } #[derive(CandidType, Deserialize)] -pub enum ecdsa_curve { secp256k1 } +pub enum EcdsaCurve { #[serde(rename="secp256k1")] Secp256K1 } #[derive(CandidType, Deserialize)] -pub struct ecdsa_public_key_arg0_key_id { name: String, curve: ecdsa_curve } +pub struct EcdsaPublicKeyArgKeyId { name: String, curve: EcdsaCurve } #[derive(CandidType, Deserialize)] -pub struct ecdsa_public_key_arg0 { - key_id: ecdsa_public_key_arg0_key_id, - canister_id: Option, +pub struct EcdsaPublicKeyArg { + key_id: EcdsaPublicKeyArgKeyId, + canister_id: Option, derivation_path: Vec, } #[derive(CandidType, Deserialize)] -pub struct ecdsa_public_key_ret0 { +pub struct EcdsaPublicKeyRet { public_key: serde_bytes::ByteBuf, chain_code: serde_bytes::ByteBuf, } #[derive(CandidType, Deserialize)] -pub enum http_request_arg0_method { get, head, post } +pub enum HttpRequestArgMethod { + #[serde(rename="get")] + Get, + #[serde(rename="head")] + Head, + #[serde(rename="post")] + Post, +} #[derive(CandidType, Deserialize)] -pub struct http_header { value: String, name: String } +pub struct HttpHeader { value: String, name: String } #[derive(CandidType, Deserialize)] -pub struct http_response { +pub struct HttpResponse { status: candid::Nat, body: serde_bytes::ByteBuf, - headers: Vec, + headers: Vec, } #[derive(CandidType, Deserialize)] -pub struct http_request_arg0_transform_inner_function_arg0 { +pub struct HttpRequestArgTransformInnerFunctionArg { context: serde_bytes::ByteBuf, - response: http_response, + response: HttpResponse, } -candid::define_function!(pub http_request_arg0_transform_inner_function : ( - http_request_arg0_transform_inner_function_arg0, - ) -> (http_response) query); +candid::define_function!(pub HttpRequestArgTransformInnerFunction : ( + HttpRequestArgTransformInnerFunctionArg, + ) -> (HttpResponse) query); #[derive(CandidType, Deserialize)] -pub struct http_request_arg0_transform_inner { - function: http_request_arg0_transform_inner_function, +pub struct HttpRequestArgTransformInner { + function: HttpRequestArgTransformInnerFunction, context: serde_bytes::ByteBuf, } #[derive(CandidType, Deserialize)] -pub struct http_request_arg0 { +pub struct HttpRequestArg { url: String, - method: http_request_arg0_method, + method: HttpRequestArgMethod, max_response_bytes: Option, body: Option, - transform: Option, - headers: Vec, + transform: Option, + headers: Vec, } -pub type wasm_module = serde_bytes::ByteBuf; +pub type WasmModule = serde_bytes::ByteBuf; #[derive(CandidType, Deserialize)] -pub enum install_code_arg0_mode { reinstall, upgrade, install } +pub enum InstallCodeArgMode { + #[serde(rename="reinstall")] + Reinstall, + #[serde(rename="upgrade")] + Upgrade, + #[serde(rename="install")] + Install, +} #[derive(CandidType, Deserialize)] -pub struct install_code_arg0 { +pub struct InstallCodeArg { arg: serde_bytes::ByteBuf, - wasm_module: wasm_module, - mode: install_code_arg0_mode, - canister_id: canister_id, + wasm_module: WasmModule, + mode: InstallCodeArgMode, + canister_id: CanisterId, } #[derive(CandidType, Deserialize)] -pub struct provisional_create_canister_with_cycles_arg0 { - settings: Option, - specified_id: Option, +pub struct ProvisionalCreateCanisterWithCyclesArg { + settings: Option, + specified_id: Option, amount: Option, } #[derive(CandidType, Deserialize)] -pub struct provisional_create_canister_with_cycles_ret0 { - canister_id: canister_id, -} +pub struct ProvisionalCreateCanisterWithCyclesRet { canister_id: CanisterId } #[derive(CandidType, Deserialize)] -pub struct provisional_top_up_canister_arg0 { - canister_id: canister_id, +pub struct ProvisionalTopUpCanisterArg { + canister_id: CanisterId, amount: candid::Nat, } #[derive(CandidType, Deserialize)] -pub struct sign_with_ecdsa_arg0_key_id { name: String, curve: ecdsa_curve } +pub struct SignWithEcdsaArgKeyId { name: String, curve: EcdsaCurve } #[derive(CandidType, Deserialize)] -pub struct sign_with_ecdsa_arg0 { - key_id: sign_with_ecdsa_arg0_key_id, +pub struct SignWithEcdsaArg { + key_id: SignWithEcdsaArgKeyId, derivation_path: Vec, message_hash: serde_bytes::ByteBuf, } #[derive(CandidType, Deserialize)] -pub struct sign_with_ecdsa_ret0 { signature: serde_bytes::ByteBuf } +pub struct SignWithEcdsaRet { signature: serde_bytes::ByteBuf } #[derive(CandidType, Deserialize)] -pub struct start_canister_arg0 { canister_id: canister_id } +pub struct StartCanisterArg { canister_id: CanisterId } #[derive(CandidType, Deserialize)] -pub struct stop_canister_arg0 { canister_id: canister_id } +pub struct StopCanisterArg { canister_id: CanisterId } #[derive(CandidType, Deserialize)] -pub struct uninstall_code_arg0 { canister_id: canister_id } +pub struct UninstallCodeArg { canister_id: CanisterId } #[derive(CandidType, Deserialize)] -pub struct update_settings_arg0 { +pub struct UpdateSettingsArg { canister_id: Principal, - settings: canister_settings, + settings: CanisterSettings, } pub struct SERVICE(pub Principal); impl SERVICE { pub async fn bitcoin_get_balance( &self, agent: &ic_agent::Agent, - arg0: get_balance_request, - ) -> Result { + arg0: GetBalanceRequest, + ) -> Result { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "bitcoin_get_balance").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, satoshi)?) + Ok(candid::Decode!(&bytes, Satoshi)?) } pub async fn bitcoin_get_current_fee_percentiles( &self, agent: &ic_agent::Agent, - arg0: get_current_fee_percentiles_request, - ) -> Result> { + arg0: GetCurrentFeePercentilesRequest, + ) -> Result> { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "bitcoin_get_current_fee_percentiles").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, Vec)?) + Ok(candid::Decode!(&bytes, Vec)?) } pub async fn bitcoin_get_utxos( &self, agent: &ic_agent::Agent, - arg0: get_utxos_request, - ) -> Result { + arg0: GetUtxosRequest, + ) -> Result { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "bitcoin_get_utxos").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, get_utxos_response)?) + Ok(candid::Decode!(&bytes, GetUtxosResponse)?) } pub async fn bitcoin_send_transaction( &self, agent: &ic_agent::Agent, - arg0: send_transaction_request, + arg0: SendTransactionRequest, ) -> Result<()> { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "bitcoin_send_transaction").with_arg(args).call_and_wait().await?; @@ -248,23 +274,23 @@ impl SERVICE { } pub async fn canister_status( &self, agent: &ic_agent::Agent, - arg0: canister_status_arg0, - ) -> Result { + arg0: CanisterStatusArg, + ) -> Result { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "canister_status").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, canister_status_ret0)?) + Ok(candid::Decode!(&bytes, CanisterStatusRet)?) } pub async fn create_canister( &self, agent: &ic_agent::Agent, - arg0: create_canister_arg0, - ) -> Result { + arg0: CreateCanisterArg, + ) -> Result { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "create_canister").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, create_canister_ret0)?) + Ok(candid::Decode!(&bytes, CreateCanisterRet)?) } pub async fn delete_canister( &self, agent: &ic_agent::Agent, - arg0: delete_canister_arg0, + arg0: DeleteCanisterArg, ) -> Result<()> { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "delete_canister").with_arg(args).call_and_wait().await?; @@ -272,7 +298,7 @@ impl SERVICE { } pub async fn deposit_cycles( &self, agent: &ic_agent::Agent, - arg0: deposit_cycles_arg0, + arg0: DepositCyclesArg, ) -> Result<()> { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "deposit_cycles").with_arg(args).call_and_wait().await?; @@ -280,23 +306,23 @@ impl SERVICE { } pub async fn ecdsa_public_key( &self, agent: &ic_agent::Agent, - arg0: ecdsa_public_key_arg0, - ) -> Result { + arg0: EcdsaPublicKeyArg, + ) -> Result { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "ecdsa_public_key").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, ecdsa_public_key_ret0)?) + Ok(candid::Decode!(&bytes, EcdsaPublicKeyRet)?) } pub async fn http_request( &self, agent: &ic_agent::Agent, - arg0: http_request_arg0, - ) -> Result { + arg0: HttpRequestArg, + ) -> Result { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "http_request").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, http_response)?) + Ok(candid::Decode!(&bytes, HttpResponse)?) } pub async fn install_code( &self, agent: &ic_agent::Agent, - arg0: install_code_arg0, + arg0: InstallCodeArg, ) -> Result<()> { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "install_code").with_arg(args).call_and_wait().await?; @@ -304,15 +330,15 @@ impl SERVICE { } pub async fn provisional_create_canister_with_cycles( &self, agent: &ic_agent::Agent, - arg0: provisional_create_canister_with_cycles_arg0, - ) -> Result { + arg0: ProvisionalCreateCanisterWithCyclesArg, + ) -> Result { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "provisional_create_canister_with_cycles").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, provisional_create_canister_with_cycles_ret0)?) + Ok(candid::Decode!(&bytes, ProvisionalCreateCanisterWithCyclesRet)?) } pub async fn provisional_top_up_canister( &self, agent: &ic_agent::Agent, - arg0: provisional_top_up_canister_arg0, + arg0: ProvisionalTopUpCanisterArg, ) -> Result<()> { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "provisional_top_up_canister").with_arg(args).call_and_wait().await?; @@ -327,15 +353,15 @@ impl SERVICE { } pub async fn sign_with_ecdsa( &self, agent: &ic_agent::Agent, - arg0: sign_with_ecdsa_arg0, - ) -> Result { + arg0: SignWithEcdsaArg, + ) -> Result { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "sign_with_ecdsa").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, sign_with_ecdsa_ret0)?) + Ok(candid::Decode!(&bytes, SignWithEcdsaRet)?) } pub async fn start_canister( &self, agent: &ic_agent::Agent, - arg0: start_canister_arg0, + arg0: StartCanisterArg, ) -> Result<()> { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "start_canister").with_arg(args).call_and_wait().await?; @@ -343,7 +369,7 @@ impl SERVICE { } pub async fn stop_canister( &self, agent: &ic_agent::Agent, - arg0: stop_canister_arg0, + arg0: StopCanisterArg, ) -> Result<()> { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "stop_canister").with_arg(args).call_and_wait().await?; @@ -351,7 +377,7 @@ impl SERVICE { } pub async fn uninstall_code( &self, agent: &ic_agent::Agent, - arg0: uninstall_code_arg0, + arg0: UninstallCodeArg, ) -> Result<()> { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "uninstall_code").with_arg(args).call_and_wait().await?; @@ -359,7 +385,7 @@ impl SERVICE { } pub async fn update_settings( &self, agent: &ic_agent::Agent, - arg0: update_settings_arg0, + arg0: UpdateSettingsArg, ) -> Result<()> { let args = candid::Encode!(arg0)?; let bytes = agent.update(self.0, "update_settings").with_arg(args).call_and_wait().await?; diff --git a/rust/candid/tests/assets/ok/recursion.rs b/rust/candid/tests/assets/ok/recursion.rs index 9660947c..6be79996 100644 --- a/rust/candid/tests/assets/ok/recursion.rs +++ b/rust/candid/tests/assets/ok/recursion.rs @@ -3,40 +3,42 @@ use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; -candid::define_function!(pub t : (s) -> ()); +candid::define_function!(pub T : (S) -> ()); #[derive(CandidType, Deserialize)] -pub struct node { head: candid::Nat, tail: Box } +pub struct Node { head: candid::Nat, tail: Box } #[derive(CandidType, Deserialize)] -pub struct list(Option); +pub struct List(Option); pub type A = Box; #[derive(CandidType, Deserialize)] pub struct B(Option); #[derive(CandidType, Deserialize)] -pub enum tree { - branch{ val: candid::Int, left: Box, right: Box }, - leaf(candid::Int), +pub enum Tree { + #[serde(rename="branch")] + Branch{ val: candid::Int, left: Box, right: Box }, + #[serde(rename="leaf")] + Leaf(candid::Int), } -candid::define_function!(pub stream_inner_next : () -> (stream) query); +candid::define_function!(pub StreamInnerNext : () -> (Stream) query); #[derive(CandidType, Deserialize)] -pub struct stream_inner { head: candid::Nat, next: stream_inner_next } +pub struct StreamInner { head: candid::Nat, next: StreamInnerNext } #[derive(CandidType, Deserialize)] -pub struct stream(Option); +pub struct Stream(Option); -candid::define_service!(pub s : { - "f" : t::ty(); - "g" : candid::func!((list) -> (B, tree, stream)); +candid::define_service!(pub S : { + "f" : T::ty(); + "g" : candid::func!((List) -> (B, Tree, Stream)); }); pub struct SERVICE(pub Principal); impl SERVICE { - pub async fn f(&self, arg0: s) -> Result<()> { + pub async fn f(&self, arg0: S) -> Result<()> { ic_cdk::call(self.0, "f", (arg0,)).await } - pub async fn g(&self, arg0: list) -> Result<(B,tree,stream,)> { + pub async fn g(&self, arg0: List) -> Result<(B,Tree,Stream,)> { ic_cdk::call(self.0, "g", (arg0,)).await } } diff --git a/rust/candid/tests/assets/ok/recursive_class.rs b/rust/candid/tests/assets/ok/recursive_class.rs index 50c14176..68651224 100644 --- a/rust/candid/tests/assets/ok/recursive_class.rs +++ b/rust/candid/tests/assets/ok/recursive_class.rs @@ -3,10 +3,10 @@ use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; -candid::define_service!(pub s : { "next" : candid::func!(() -> (s)) }); +candid::define_service!(pub S : { "next" : candid::func!(() -> (S)) }); pub struct SERVICE(pub Principal); impl SERVICE { - pub async fn next(&self) -> Result<(s,)> { + pub async fn next(&self) -> Result<(S,)> { ic_cdk::call(self.0, "next", ()).await } } diff --git a/rust/candid/tests/assets/ok/service.rs b/rust/candid/tests/assets/ok/service.rs index 6050e8f4..1584278c 100644 --- a/rust/candid/tests/assets/ok/service.rs +++ b/rust/candid/tests/assets/ok/service.rs @@ -7,7 +7,12 @@ candid::define_function!(pub Func : () -> (Service)); candid::define_service!(pub Service : { "f" : Func::ty() }); pub type Service2 = Box; #[derive(CandidType, Deserialize)] -pub enum asVariant_ret0 { a(Service2), b{ f: Option } } +pub enum AsVariantRet { + #[serde(rename="a")] + A(Service2), + #[serde(rename="b")] + B{ f: Option }, +} pub struct SERVICE(pub Principal); impl SERVICE { @@ -20,7 +25,7 @@ impl SERVICE { pub async fn asRecord(&self) -> Result<((Service2,Option,Func,),)> { ic_cdk::call(self.0, "asRecord", ()).await } - pub async fn asVariant(&self) -> Result<(asVariant_ret0,)> { + pub async fn asVariant(&self) -> Result<(AsVariantRet,)> { ic_cdk::call(self.0, "asVariant", ()).await } } From 252ba86d4b09427588391e21b41599736301194d Mon Sep 17 00:00:00 2001 From: Yan Chen Date: Mon, 21 Aug 2023 20:32:38 -0700 Subject: [PATCH 2/7] agent codegen builds --- rust/candid/src/bindings/rust.rs | 19 ++++++++++++------- rust/candid/src/types/internal.rs | 2 +- rust/candid/src/types/reference.rs | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/rust/candid/src/bindings/rust.rs b/rust/candid/src/bindings/rust.rs index 9d075a2d..cf62a65c 100644 --- a/rust/candid/src/bindings/rust.rs +++ b/rust/candid/src/bindings/rust.rs @@ -70,7 +70,7 @@ fn ident_(id: &str, case: Option) -> (RcDoc, bool) { } else { (false, id.to_owned()) }; - if ["crate", "self", "super", "Self", "Result"].contains(&id.as_str()) { + if ["crate", "self", "super", "Self", "Result", "Principal"].contains(&id.as_str()) { (RcDoc::text(format!("{id}_")), true) } else if KEYWORDS.contains(&id.as_str()) { (RcDoc::text(format!("r#{id}")), is_rename) @@ -278,7 +278,7 @@ fn pp_ty_service(serv: &[(String, Type)]) -> RcDoc { } fn pp_function<'a>(config: &Config, id: &'a str, func: &'a Function) -> RcDoc<'a> { - let name = ident(id, None); + let name = ident(id, Some(Case::Snake)); let empty = BTreeSet::new(); let arg_prefix = str(match config.target { Target::CanisterCall => "&self", @@ -334,19 +334,23 @@ fn pp_function<'a>(config: &Config, id: &'a str, func: &'a Function) -> RcDoc<'a let builder_method = if is_query { "query" } else { "update" }; let call = if is_query { "call" } else { "call_and_wait" }; let args = RcDoc::intersperse( - (0..func.args.len()).map(|i| RcDoc::text(format!("arg{i}"))), + (0..func.args.len()).map(|i| RcDoc::text(format!("&arg{i}"))), RcDoc::text(", "), ); - let blob = str("candid::Encode!").append(enclose("(", args, ")?;")); + let blob = str("Encode!").append(enclose( + "(", + args, + ").map_err(|e| ic_agent::AgentError::CandidError(e.into()))?;", + )); let rets = RcDoc::concat( func.rets .iter() .map(|ty| str(", ").append(pp_ty(ty, &empty))), ); str("let args = ").append(blob).append(RcDoc::hardline()) - .append(format!("let bytes = agent.{builder_method}(self.0, \"{method}\").with_arg(args).{call}().await?;")) + .append(format!("let bytes = agent.{builder_method}(&self.0, \"{method}\").with_arg(args).{call}().await?;")) .append(RcDoc::hardline()) - .append("Ok(candid::Decode!(&bytes").append(rets).append(")?)") + .append("Decode!(&bytes").append(rets).append(").map_err(|e| ic_agent::AgentError::CandidError(e.into()))") } Target::CanisterStub => unimplemented!(), }; @@ -388,7 +392,8 @@ pub fn compile(config: &Config, env: &TypeEnv, actor: &Option) -> String { let header = format!( r#"// This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -use {}::{{self, CandidType, Deserialize, Principal}}; +#![allow(dead_code)] +use {}::{{self, CandidType, Deserialize, Principal, Encode, Decode}}; "#, config.candid_crate ); diff --git a/rust/candid/src/types/internal.rs b/rust/candid/src/types/internal.rs index 1d2f0919..ed1c9674 100644 --- a/rust/candid/src/types/internal.rs +++ b/rust/candid/src/types/internal.rs @@ -444,7 +444,7 @@ macro_rules! func { /// /// `service!{ "f": func!((HttpRequest) -> ()) }` expands to `Type(Rc::new(TypeInner::Service(...)))` macro_rules! service { - { $($meth:tt : $ty:expr);* } => {{ + { $($meth:tt : $ty:expr);* $(;)? } => {{ let mut ms = vec![ $(($meth.to_string(), $ty)),* ]; ms.sort_unstable_by(|a, b| a.0.as_str().partial_cmp(b.0.as_str()).unwrap()); if let Err(e) = $crate::utils::check_unique(ms.iter().map(|m| &m.0)) { diff --git a/rust/candid/src/types/reference.rs b/rust/candid/src/types/reference.rs index 568c987a..7cbb4dd9 100644 --- a/rust/candid/src/types/reference.rs +++ b/rust/candid/src/types/reference.rs @@ -60,7 +60,7 @@ macro_rules! define_service { fn _ty() -> $crate::types::Type { $crate::service!{$($ty)*} } - fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> + fn idl_serialize(&self, serializer: S) -> std::result::Result<(), S::Error> { self.0.idl_serialize(serializer) } From 65220e4a04fe0464f2eefe90542a4e99cb60e2a9 Mon Sep 17 00:00:00 2001 From: Yan Chen Date: Wed, 23 Aug 2023 19:16:54 -0700 Subject: [PATCH 3/7] fix --- rust/candid/src/types/reference.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/candid/src/types/reference.rs b/rust/candid/src/types/reference.rs index 7cbb4dd9..4a314319 100644 --- a/rust/candid/src/types/reference.rs +++ b/rust/candid/src/types/reference.rs @@ -31,7 +31,7 @@ macro_rules! define_function { fn _ty() -> $crate::types::Type { $crate::func!($($ty)+) } - fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> + fn idl_serialize(&self, serializer: S) -> std::result::Result<(), S::Error> { self.0.idl_serialize(serializer) } From 8bd706f07e69e88646f7887e70ff0fb84f9ae719 Mon Sep 17 00:00:00 2001 From: Yan Chen Date: Thu, 24 Aug 2023 21:27:05 -0700 Subject: [PATCH 4/7] fix --- rust/candid/src/bindings/rust.rs | 51 ++-- rust/candid/tests/assets/ok/actor.rs | 10 +- rust/candid/tests/assets/ok/class.rs | 10 +- rust/candid/tests/assets/ok/comment.rs | 3 +- rust/candid/tests/assets/ok/cyclic.rs | 10 +- rust/candid/tests/assets/ok/escape.rs | 10 +- rust/candid/tests/assets/ok/example.rs | 10 +- rust/candid/tests/assets/ok/fieldnat.rs | 10 +- rust/candid/tests/assets/ok/keyword.rs | 16 +- rust/candid/tests/assets/ok/management.rs | 221 ++++++++---------- rust/candid/tests/assets/ok/recursion.rs | 10 +- .../candid/tests/assets/ok/recursive_class.rs | 10 +- rust/candid/tests/assets/ok/service.rs | 18 +- rust/candid/tests/assets/ok/unicode.rs | 10 +- 14 files changed, 207 insertions(+), 192 deletions(-) diff --git a/rust/candid/src/bindings/rust.rs b/rust/candid/src/bindings/rust.rs index cf62a65c..4069ec12 100644 --- a/rust/candid/src/bindings/rust.rs +++ b/rust/candid/src/bindings/rust.rs @@ -282,7 +282,7 @@ fn pp_function<'a>(config: &Config, id: &'a str, func: &'a Function) -> RcDoc<'a let empty = BTreeSet::new(); let arg_prefix = str(match config.target { Target::CanisterCall => "&self", - Target::Agent => "&self, agent: &ic_agent::Agent", + Target::Agent => "&self", Target::CanisterStub => unimplemented!(), }); let args = concat( @@ -337,20 +337,16 @@ fn pp_function<'a>(config: &Config, id: &'a str, func: &'a Function) -> RcDoc<'a (0..func.args.len()).map(|i| RcDoc::text(format!("&arg{i}"))), RcDoc::text(", "), ); - let blob = str("Encode!").append(enclose( - "(", - args, - ").map_err(|e| ic_agent::AgentError::CandidError(e.into()))?;", - )); + let blob = str("Encode!").append(enclose("(", args, ")?;")); let rets = RcDoc::concat( func.rets .iter() .map(|ty| str(", ").append(pp_ty(ty, &empty))), ); str("let args = ").append(blob).append(RcDoc::hardline()) - .append(format!("let bytes = agent.{builder_method}(&self.0, \"{method}\").with_arg(args).{call}().await?;")) + .append(format!("let bytes = self.1.{builder_method}(&self.0, \"{method}\").with_arg(args).{call}().await?;")) .append(RcDoc::hardline()) - .append("Decode!(&bytes").append(rets).append(").map_err(|e| ic_agent::AgentError::CandidError(e.into()))") + .append("Ok(Decode!(&bytes").append(rets).append(")?)") } Target::CanisterStub => unimplemented!(), }; @@ -367,9 +363,23 @@ fn pp_actor<'a>(config: &'a Config, env: &'a TypeEnv, actor: &'a Type) -> RcDoc< }), RcDoc::hardline(), ); - let res = RcDoc::text("pub struct SERVICE(pub Principal);") + let struct_name = config.service_name.to_case(Case::Pascal); + let service_def = match config.target { + Target::CanisterCall => format!("pub struct {}(pub Principal);", struct_name), + Target::Agent => format!( + "pub struct {}<'a>(pub Principal, pub &'a ic_agent::Agent);", + struct_name + ), + Target::CanisterStub => unimplemented!(), + }; + let service_impl = match config.target { + Target::CanisterCall => format!("impl {} ", struct_name), + Target::Agent => format!("impl<'a> {}<'a> ", struct_name), + Target::CanisterStub => unimplemented!(), + }; + let res = RcDoc::text(service_def) .append(RcDoc::hardline()) - .append("impl SERVICE ") + .append(service_impl) .append(enclose_space("{", body, "}")) .append(RcDoc::hardline()); if let Some(cid) = config.canister_id { @@ -379,10 +389,19 @@ fn pp_actor<'a>(config: &'a Config, env: &'a TypeEnv, actor: &'a Type) -> RcDoc< .map(|b| b.to_string()) .collect::>() .join(", "); - res.append(format!( - r#"pub const {}: SERVICE = SERVICE(Principal::from_slice(&[{}])); // {}"#, - config.service_name, slice, cid - )) + let id = RcDoc::text(format!( + "pub const CANISTER_ID : Principal = Principal::from_slice(&[{}]); // {}", + slice, cid + )); + let instance = match config.target { + Target::CanisterCall => format!( + "pub const {} : {} = {}(CANISTER_ID);", + config.service_name, struct_name, struct_name + ), + Target::Agent => "".to_string(), + Target::CanisterStub => unimplemented!(), + }; + res.append(id).append(RcDoc::hardline()).append(instance) } else { res } @@ -392,7 +411,7 @@ pub fn compile(config: &Config, env: &TypeEnv, actor: &Option) -> String { let header = format!( r#"// This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -#![allow(dead_code)] +#![allow(dead_code, unused_imports)] use {}::{{self, CandidType, Deserialize, Principal, Encode, Decode}}; "#, config.candid_crate @@ -400,7 +419,7 @@ use {}::{{self, CandidType, Deserialize, Principal, Encode, Decode}}; let header = header + match &config.target { Target::CanisterCall => "use ic_cdk::api::call::CallResult as Result;\n", - Target::Agent => "type Result = std::result::Result;", + Target::Agent => "type Result = std::result::Result;\n", Target::CanisterStub => "", }; let (env, actor) = nominalize_all(env, actor); diff --git a/rust/candid/tests/assets/ok/actor.rs b/rust/candid/tests/assets/ok/actor.rs index 47f70fa4..2f2dc6ad 100644 --- a/rust/candid/tests/assets/ok/actor.rs +++ b/rust/candid/tests/assets/ok/actor.rs @@ -1,6 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -use candid::{self, CandidType, Deserialize, Principal}; +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; use ic_cdk::api::call::CallResult as Result; candid::define_function!(pub F : (i8) -> (i8)); @@ -9,8 +10,8 @@ pub type G = F; #[derive(CandidType, Deserialize)] pub struct O(Option>); -pub struct SERVICE(pub Principal); -impl SERVICE { +pub struct Service(pub Principal); +impl Service { pub async fn f(&self, arg0: candid::Nat) -> Result<(H,)> { ic_cdk::call(self.0, "f", (arg0,)).await } @@ -24,4 +25,5 @@ impl SERVICE { ic_cdk::call(self.0, "o", (arg0,)).await } } -pub const service: SERVICE = SERVICE(Principal::from_slice(&[])); // aaaaa-aa +pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa +pub const service : Service = Service(CANISTER_ID); diff --git a/rust/candid/tests/assets/ok/class.rs b/rust/candid/tests/assets/ok/class.rs index 0a2b6bdb..17a8df14 100644 --- a/rust/candid/tests/assets/ok/class.rs +++ b/rust/candid/tests/assets/ok/class.rs @@ -1,13 +1,14 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -use candid::{self, CandidType, Deserialize, Principal}; +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] pub struct List(Option<(candid::Int,Box,)>); -pub struct SERVICE(pub Principal); -impl SERVICE { +pub struct Service(pub Principal); +impl Service { pub async fn get(&self) -> Result<(List,)> { ic_cdk::call(self.0, "get", ()).await } @@ -15,4 +16,5 @@ impl SERVICE { ic_cdk::call(self.0, "set", (arg0,)).await } } -pub const service: SERVICE = SERVICE(Principal::from_slice(&[])); // aaaaa-aa +pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa +pub const service : Service = Service(CANISTER_ID); diff --git a/rust/candid/tests/assets/ok/comment.rs b/rust/candid/tests/assets/ok/comment.rs index 36a16f68..4839a3f7 100644 --- a/rust/candid/tests/assets/ok/comment.rs +++ b/rust/candid/tests/assets/ok/comment.rs @@ -1,6 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -use candid::{self, CandidType, Deserialize, Principal}; +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; use ic_cdk::api::call::CallResult as Result; pub type Id = u8; diff --git a/rust/candid/tests/assets/ok/cyclic.rs b/rust/candid/tests/assets/ok/cyclic.rs index dbd62c0e..cb7c2821 100644 --- a/rust/candid/tests/assets/ok/cyclic.rs +++ b/rust/candid/tests/assets/ok/cyclic.rs @@ -1,6 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -use candid::{self, CandidType, Deserialize, Principal}; +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; use ic_cdk::api::call::CallResult as Result; pub type C = Box; @@ -11,8 +12,8 @@ pub struct A(Option); pub type Z = Box; pub type Y = Z; pub type X = Y; -pub struct SERVICE(pub Principal); -impl SERVICE { +pub struct Service(pub Principal); +impl Service { pub async fn f( &self, arg0: A, @@ -25,4 +26,5 @@ impl SERVICE { ic_cdk::call(self.0, "f", (arg0,arg1,arg2,arg3,arg4,arg5,)).await } } -pub const service: SERVICE = SERVICE(Principal::from_slice(&[])); // aaaaa-aa +pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa +pub const service : Service = Service(CANISTER_ID); diff --git a/rust/candid/tests/assets/ok/escape.rs b/rust/candid/tests/assets/ok/escape.rs index 1dfbb98c..597a887c 100644 --- a/rust/candid/tests/assets/ok/escape.rs +++ b/rust/candid/tests/assets/ok/escape.rs @@ -1,6 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -use candid::{self, CandidType, Deserialize, Principal}; +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] @@ -15,10 +16,11 @@ pub struct T { _1020746185_: candid::Nat, } -pub struct SERVICE(pub Principal); -impl SERVICE { +pub struct Service(pub Principal); +impl Service { pub async fn _2635468193_(&self, arg0: T) -> Result<()> { ic_cdk::call(self.0, "\n\'\"\'\'\"\"\r\t", (arg0,)).await } } -pub const service: SERVICE = SERVICE(Principal::from_slice(&[])); // aaaaa-aa +pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa +pub const service : Service = Service(CANISTER_ID); diff --git a/rust/candid/tests/assets/ok/example.rs b/rust/candid/tests/assets/ok/example.rs index 5eccfa9d..e054f72f 100644 --- a/rust/candid/tests/assets/ok/example.rs +++ b/rust/candid/tests/assets/ok/example.rs @@ -1,6 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -use candid::{self, CandidType, Deserialize, Principal}; +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] @@ -57,8 +58,8 @@ pub struct B (candid::Int,candid::Nat,); #[derive(CandidType, Deserialize)] pub enum A { #[serde(rename="a")] A, #[serde(rename="b")] B(B) } -pub struct SERVICE(pub Principal); -impl SERVICE { +pub struct Service(pub Principal); +impl Service { pub async fn f( &self, arg0: List, @@ -87,4 +88,5 @@ impl SERVICE { ic_cdk::call(self.0, "x", (arg0,arg1,)).await } } -pub const service: SERVICE = SERVICE(Principal::from_slice(&[])); // aaaaa-aa +pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa +pub const service : Service = Service(CANISTER_ID); diff --git a/rust/candid/tests/assets/ok/fieldnat.rs b/rust/candid/tests/assets/ok/fieldnat.rs index d79cde40..af18e604 100644 --- a/rust/candid/tests/assets/ok/fieldnat.rs +++ b/rust/candid/tests/assets/ok/fieldnat.rs @@ -1,6 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -use candid::{self, CandidType, Deserialize, Principal}; +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] @@ -30,8 +31,8 @@ pub struct FooArg { _2_: candid::Int } #[derive(CandidType, Deserialize)] pub struct FooRet { _2_: candid::Int, _2: candid::Int } -pub struct SERVICE(pub Principal); -impl SERVICE { +pub struct Service(pub Principal); +impl Service { pub async fn bab(&self, arg0: candid::Int, arg1: candid::Nat) -> Result<()> { ic_cdk::call(self.0, "bab", (arg0,arg1,)).await } @@ -54,4 +55,5 @@ impl SERVICE { ic_cdk::call(self.0, "foo", (arg0,)).await } } -pub const service: SERVICE = SERVICE(Principal::from_slice(&[])); // aaaaa-aa +pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa +pub const service : Service = Service(CANISTER_ID); diff --git a/rust/candid/tests/assets/ok/keyword.rs b/rust/candid/tests/assets/ok/keyword.rs index f4f36051..fc4e9bc5 100644 --- a/rust/candid/tests/assets/ok/keyword.rs +++ b/rust/candid/tests/assets/ok/keyword.rs @@ -1,6 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -use candid::{self, CandidType, Deserialize, Principal}; +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] @@ -48,12 +49,12 @@ candid::define_function!(pub T : (Return) -> ()); #[derive(CandidType, Deserialize)] pub enum VariantArg { A, B, C, D(f64) } -pub struct SERVICE(pub Principal); -impl SERVICE { - pub async fn Oneway(&self) -> Result<()> { +pub struct Service(pub Principal); +impl Service { + pub async fn oneway(&self) -> Result<()> { ic_cdk::call(self.0, "Oneway", ()).await } - pub async fn f_(&self, arg0: O) -> Result<(O,)> { + pub async fn f(&self, arg0: O) -> Result<(O,)> { ic_cdk::call(self.0, "f_", (arg0,)).await } pub async fn field(&self, arg0: FieldArg) -> Result<(FieldRet,)> { @@ -65,7 +66,7 @@ impl SERVICE { pub async fn oneway(&self, arg0: u8) -> Result<()> { ic_cdk::call(self.0, "oneway", (arg0,)).await } - pub async fn oneway_(&self, arg0: u8) -> Result<()> { + pub async fn oneway(&self, arg0: u8) -> Result<()> { ic_cdk::call(self.0, "oneway_", (arg0,)).await } pub async fn query(&self, arg0: serde_bytes::ByteBuf) -> Result< @@ -87,4 +88,5 @@ impl SERVICE { ic_cdk::call(self.0, "variant", (arg0,)).await } } -pub const service: SERVICE = SERVICE(Principal::from_slice(&[])); // aaaaa-aa +pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa +pub const service : Service = Service(CANISTER_ID); diff --git a/rust/candid/tests/assets/ok/management.rs b/rust/candid/tests/assets/ok/management.rs index ef2f1338..48d784ca 100644 --- a/rust/candid/tests/assets/ok/management.rs +++ b/rust/candid/tests/assets/ok/management.rs @@ -1,7 +1,9 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -use candid::{self, CandidType, Deserialize, Principal}; +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; type Result = std::result::Result; + #[derive(CandidType, Deserialize)] pub enum BitcoinNetwork { #[serde(rename="mainnet")] @@ -238,158 +240,129 @@ pub struct UpdateSettingsArg { settings: CanisterSettings, } -pub struct SERVICE(pub Principal); -impl SERVICE { - pub async fn bitcoin_get_balance( - &self, agent: &ic_agent::Agent, - arg0: GetBalanceRequest, - ) -> Result { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "bitcoin_get_balance").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, Satoshi)?) +pub struct Service<'a>(pub Principal, pub &'a ic_agent::Agent); +impl<'a> Service<'a> { + pub async fn bitcoin_get_balance(&self, arg0: GetBalanceRequest) -> Result< + Satoshi + > { + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "bitcoin_get_balance").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes, Satoshi)?) } pub async fn bitcoin_get_current_fee_percentiles( - &self, agent: &ic_agent::Agent, + &self, arg0: GetCurrentFeePercentilesRequest, ) -> Result> { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "bitcoin_get_current_fee_percentiles").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, Vec)?) + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "bitcoin_get_current_fee_percentiles").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes, Vec)?) } - pub async fn bitcoin_get_utxos( - &self, agent: &ic_agent::Agent, - arg0: GetUtxosRequest, - ) -> Result { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "bitcoin_get_utxos").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, GetUtxosResponse)?) + pub async fn bitcoin_get_utxos(&self, arg0: GetUtxosRequest) -> Result< + GetUtxosResponse + > { + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "bitcoin_get_utxos").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes, GetUtxosResponse)?) } pub async fn bitcoin_send_transaction( - &self, agent: &ic_agent::Agent, + &self, arg0: SendTransactionRequest, ) -> Result<()> { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "bitcoin_send_transaction").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes)?) + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "bitcoin_send_transaction").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes)?) } - pub async fn canister_status( - &self, agent: &ic_agent::Agent, - arg0: CanisterStatusArg, - ) -> Result { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "canister_status").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, CanisterStatusRet)?) + pub async fn canister_status(&self, arg0: CanisterStatusArg) -> Result< + CanisterStatusRet + > { + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "canister_status").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes, CanisterStatusRet)?) } - pub async fn create_canister( - &self, agent: &ic_agent::Agent, - arg0: CreateCanisterArg, - ) -> Result { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "create_canister").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, CreateCanisterRet)?) + pub async fn create_canister(&self, arg0: CreateCanisterArg) -> Result< + CreateCanisterRet + > { + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "create_canister").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes, CreateCanisterRet)?) } - pub async fn delete_canister( - &self, agent: &ic_agent::Agent, - arg0: DeleteCanisterArg, - ) -> Result<()> { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "delete_canister").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes)?) + pub async fn delete_canister(&self, arg0: DeleteCanisterArg) -> Result<()> { + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "delete_canister").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes)?) } - pub async fn deposit_cycles( - &self, agent: &ic_agent::Agent, - arg0: DepositCyclesArg, - ) -> Result<()> { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "deposit_cycles").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes)?) + pub async fn deposit_cycles(&self, arg0: DepositCyclesArg) -> Result<()> { + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "deposit_cycles").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes)?) } - pub async fn ecdsa_public_key( - &self, agent: &ic_agent::Agent, - arg0: EcdsaPublicKeyArg, - ) -> Result { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "ecdsa_public_key").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, EcdsaPublicKeyRet)?) + pub async fn ecdsa_public_key(&self, arg0: EcdsaPublicKeyArg) -> Result< + EcdsaPublicKeyRet + > { + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "ecdsa_public_key").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes, EcdsaPublicKeyRet)?) } - pub async fn http_request( - &self, agent: &ic_agent::Agent, - arg0: HttpRequestArg, - ) -> Result { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "http_request").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, HttpResponse)?) + pub async fn http_request(&self, arg0: HttpRequestArg) -> Result< + HttpResponse + > { + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "http_request").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes, HttpResponse)?) } - pub async fn install_code( - &self, agent: &ic_agent::Agent, - arg0: InstallCodeArg, - ) -> Result<()> { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "install_code").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes)?) + pub async fn install_code(&self, arg0: InstallCodeArg) -> Result<()> { + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "install_code").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes)?) } pub async fn provisional_create_canister_with_cycles( - &self, agent: &ic_agent::Agent, + &self, arg0: ProvisionalCreateCanisterWithCyclesArg, ) -> Result { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "provisional_create_canister_with_cycles").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, ProvisionalCreateCanisterWithCyclesRet)?) + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "provisional_create_canister_with_cycles").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes, ProvisionalCreateCanisterWithCyclesRet)?) } pub async fn provisional_top_up_canister( - &self, agent: &ic_agent::Agent, + &self, arg0: ProvisionalTopUpCanisterArg, ) -> Result<()> { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "provisional_top_up_canister").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes)?) + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "provisional_top_up_canister").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes)?) } - pub async fn raw_rand(&self, agent: &ic_agent::Agent) -> Result< - serde_bytes::ByteBuf - > { - let args = candid::Encode!()?; - let bytes = agent.update(self.0, "raw_rand").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, serde_bytes::ByteBuf)?) + pub async fn raw_rand(&self) -> Result { + let args = Encode!()?; + let bytes = self.1.update(&self.0, "raw_rand").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes, serde_bytes::ByteBuf)?) } - pub async fn sign_with_ecdsa( - &self, agent: &ic_agent::Agent, - arg0: SignWithEcdsaArg, - ) -> Result { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "sign_with_ecdsa").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes, SignWithEcdsaRet)?) + pub async fn sign_with_ecdsa(&self, arg0: SignWithEcdsaArg) -> Result< + SignWithEcdsaRet + > { + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "sign_with_ecdsa").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes, SignWithEcdsaRet)?) } - pub async fn start_canister( - &self, agent: &ic_agent::Agent, - arg0: StartCanisterArg, - ) -> Result<()> { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "start_canister").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes)?) + pub async fn start_canister(&self, arg0: StartCanisterArg) -> Result<()> { + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "start_canister").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes)?) } - pub async fn stop_canister( - &self, agent: &ic_agent::Agent, - arg0: StopCanisterArg, - ) -> Result<()> { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "stop_canister").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes)?) + pub async fn stop_canister(&self, arg0: StopCanisterArg) -> Result<()> { + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "stop_canister").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes)?) } - pub async fn uninstall_code( - &self, agent: &ic_agent::Agent, - arg0: UninstallCodeArg, - ) -> Result<()> { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "uninstall_code").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes)?) + pub async fn uninstall_code(&self, arg0: UninstallCodeArg) -> Result<()> { + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "uninstall_code").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes)?) } - pub async fn update_settings( - &self, agent: &ic_agent::Agent, - arg0: UpdateSettingsArg, - ) -> Result<()> { - let args = candid::Encode!(arg0)?; - let bytes = agent.update(self.0, "update_settings").with_arg(args).call_and_wait().await?; - Ok(candid::Decode!(&bytes)?) + pub async fn update_settings(&self, arg0: UpdateSettingsArg) -> Result<()> { + let args = Encode!(&arg0)?; + let bytes = self.1.update(&self.0, "update_settings").with_arg(args).call_and_wait().await?; + Ok(Decode!(&bytes)?) } } -pub const service: SERVICE = SERVICE(Principal::from_slice(&[])); // aaaaa-aa +pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa + diff --git a/rust/candid/tests/assets/ok/recursion.rs b/rust/candid/tests/assets/ok/recursion.rs index 6be79996..f773d7f7 100644 --- a/rust/candid/tests/assets/ok/recursion.rs +++ b/rust/candid/tests/assets/ok/recursion.rs @@ -1,6 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -use candid::{self, CandidType, Deserialize, Principal}; +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; use ic_cdk::api::call::CallResult as Result; candid::define_function!(pub T : (S) -> ()); @@ -33,8 +34,8 @@ candid::define_service!(pub S : { "f" : T::ty(); "g" : candid::func!((List) -> (B, Tree, Stream)); }); -pub struct SERVICE(pub Principal); -impl SERVICE { +pub struct Service(pub Principal); +impl Service { pub async fn f(&self, arg0: S) -> Result<()> { ic_cdk::call(self.0, "f", (arg0,)).await } @@ -42,4 +43,5 @@ impl SERVICE { ic_cdk::call(self.0, "g", (arg0,)).await } } -pub const service: SERVICE = SERVICE(Principal::from_slice(&[])); // aaaaa-aa +pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa +pub const service : Service = Service(CANISTER_ID); diff --git a/rust/candid/tests/assets/ok/recursive_class.rs b/rust/candid/tests/assets/ok/recursive_class.rs index 68651224..3edd2249 100644 --- a/rust/candid/tests/assets/ok/recursive_class.rs +++ b/rust/candid/tests/assets/ok/recursive_class.rs @@ -1,13 +1,15 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -use candid::{self, CandidType, Deserialize, Principal}; +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; use ic_cdk::api::call::CallResult as Result; candid::define_service!(pub S : { "next" : candid::func!(() -> (S)) }); -pub struct SERVICE(pub Principal); -impl SERVICE { +pub struct Service(pub Principal); +impl Service { pub async fn next(&self) -> Result<(S,)> { ic_cdk::call(self.0, "next", ()).await } } -pub const service: SERVICE = SERVICE(Principal::from_slice(&[])); // aaaaa-aa +pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa +pub const service : Service = Service(CANISTER_ID); diff --git a/rust/candid/tests/assets/ok/service.rs b/rust/candid/tests/assets/ok/service.rs index 1584278c..d4ac89b4 100644 --- a/rust/candid/tests/assets/ok/service.rs +++ b/rust/candid/tests/assets/ok/service.rs @@ -1,6 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -use candid::{self, CandidType, Deserialize, Principal}; +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; use ic_cdk::api::call::CallResult as Result; candid::define_function!(pub Func : () -> (Service)); @@ -14,19 +15,20 @@ pub enum AsVariantRet { B{ f: Option }, } -pub struct SERVICE(pub Principal); -impl SERVICE { - pub async fn asArray(&self) -> Result<(Vec,Vec,)> { +pub struct Service(pub Principal); +impl Service { + pub async fn as_array(&self) -> Result<(Vec,Vec,)> { ic_cdk::call(self.0, "asArray", ()).await } - pub async fn asPrincipal(&self) -> Result<(Service2,Func,)> { + pub async fn as_principal(&self) -> Result<(Service2,Func,)> { ic_cdk::call(self.0, "asPrincipal", ()).await } - pub async fn asRecord(&self) -> Result<((Service2,Option,Func,),)> { + pub async fn as_record(&self) -> Result<((Service2,Option,Func,),)> { ic_cdk::call(self.0, "asRecord", ()).await } - pub async fn asVariant(&self) -> Result<(AsVariantRet,)> { + pub async fn as_variant(&self) -> Result<(AsVariantRet,)> { ic_cdk::call(self.0, "asVariant", ()).await } } -pub const service: SERVICE = SERVICE(Principal::from_slice(&[])); // aaaaa-aa +pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa +pub const service : Service = Service(CANISTER_ID); diff --git a/rust/candid/tests/assets/ok/unicode.rs b/rust/candid/tests/assets/ok/unicode.rs index 7c473496..73dd059d 100644 --- a/rust/candid/tests/assets/ok/unicode.rs +++ b/rust/candid/tests/assets/ok/unicode.rs @@ -1,6 +1,7 @@ // This is an experimental feature to generate Rust binding from Candid. // You may want to manually adjust some of the types. -use candid::{self, CandidType, Deserialize, Principal}; +#![allow(dead_code, unused_imports)] +use candid::{self, CandidType, Deserialize, Principal, Encode, Decode}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] @@ -27,8 +28,8 @@ pub enum B { _3099250646_, } -pub struct SERVICE(pub Principal); -impl SERVICE { +pub struct Service(pub Principal); +impl Service { pub async fn _0_(&self, arg0: candid::Nat) -> Result<(candid::Nat,)> { ic_cdk::call(self.0, "", (arg0,)).await } @@ -42,4 +43,5 @@ impl SERVICE { (candid::Nat,) > { ic_cdk::call(self.0, "👀", (arg0,)).await } } -pub const service: SERVICE = SERVICE(Principal::from_slice(&[])); // aaaaa-aa +pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa +pub const service : Service = Service(CANISTER_ID); From aea664057151482656e21972d840a9077cd91e2a Mon Sep 17 00:00:00 2001 From: Yan Chen Date: Tue, 5 Sep 2023 17:07:03 -0700 Subject: [PATCH 5/7] fix --- Cargo.lock | 2 +- rust/candid/Cargo.toml | 2 +- rust/candid/src/bindings/rust.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aaa86c36..b724d8dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -257,7 +257,7 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "candid" -version = "0.9.5" +version = "0.9.6" dependencies = [ "anyhow", "arbitrary", diff --git a/rust/candid/Cargo.toml b/rust/candid/Cargo.toml index 170a253b..42150428 100644 --- a/rust/candid/Cargo.toml +++ b/rust/candid/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid" -version = "0.9.5" +version = "0.9.6" edition = "2021" authors = ["DFINITY Team"] description = "Candid is an interface description language (IDL) for interacting with canisters running on the Internet Computer." diff --git a/rust/candid/src/bindings/rust.rs b/rust/candid/src/bindings/rust.rs index 4069ec12..2e347bc4 100644 --- a/rust/candid/src/bindings/rust.rs +++ b/rust/candid/src/bindings/rust.rs @@ -62,7 +62,7 @@ fn ident_(id: &str, case: Option) -> (RcDoc, bool) { || id.starts_with(|c: char| !c.is_ascii_alphabetic() && c != '_') || id.chars().any(|c| !c.is_ascii_alphanumeric() && c != '_') { - return (RcDoc::text(format!("_{}_", crate::idl_hash(&id))), true); + return (RcDoc::text(format!("_{}_", crate::idl_hash(id))), true); } let (is_rename, id) = if let Some(case) = case { let new_id = id.to_case(case); From 8dad0091585b06a3f6d776e3941e931c72291cd4 Mon Sep 17 00:00:00 2001 From: Yan Chen Date: Tue, 5 Sep 2023 20:58:03 -0700 Subject: [PATCH 6/7] fix derive for enum::A{} --- Cargo.lock | 4 ++-- rust/candid/Cargo.toml | 2 +- rust/candid/tests/serde.rs | 8 ++++++++ rust/candid_derive/Cargo.toml | 2 +- rust/candid_derive/src/derive.rs | 26 +++++++++++--------------- tools/didc/Cargo.toml | 2 +- 6 files changed, 24 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b724d8dc..916202b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -298,7 +298,7 @@ dependencies = [ [[package]] name = "candid_derive" -version = "0.6.2" +version = "0.6.3" dependencies = [ "lazy_static", "proc-macro2 1.0.66", @@ -610,7 +610,7 @@ dependencies = [ [[package]] name = "didc" -version = "0.3.4" +version = "0.3.5" dependencies = [ "anyhow", "candid", diff --git a/rust/candid/Cargo.toml b/rust/candid/Cargo.toml index 42150428..3577941d 100644 --- a/rust/candid/Cargo.toml +++ b/rust/candid/Cargo.toml @@ -20,7 +20,7 @@ lalrpop = { version = "0.20.0", optional = true } [dependencies] byteorder = "1.4.3" -candid_derive = { path = "../candid_derive", version = "=0.6.2" } +candid_derive = { path = "../candid_derive", version = "=0.6.3" } codespan-reporting = "0.11" crc32fast = "1.3.0" data-encoding = "2.4.0" diff --git a/rust/candid/tests/serde.rs b/rust/candid/tests/serde.rs index c0722351..5fb612e8 100644 --- a/rust/candid/tests/serde.rs +++ b/rust/candid/tests/serde.rs @@ -620,6 +620,14 @@ fn test_variant() { let bytes = encode(&E::Bar(true, 42.into())); test_decode(&bytes, &None::); check_error(|| test_decode(&bytes, &Unit::Bar), "Subtyping error"); + + #[derive(PartialEq, Debug, Deserialize, CandidType)] + enum T { + A(), + B {}, + C, + } + all_check(T::A(), "4449444c026b0341014201437f6c00010000"); } #[test] diff --git a/rust/candid_derive/Cargo.toml b/rust/candid_derive/Cargo.toml index d4cf81a3..029f053e 100644 --- a/rust/candid_derive/Cargo.toml +++ b/rust/candid_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid_derive" -version = "0.6.2" +version = "0.6.3" edition = "2021" authors = ["DFINITY Team"] description = "Macros implementation of #[derive(CandidType)] for the Candid." diff --git a/rust/candid_derive/src/derive.rs b/rust/candid_derive/src/derive.rs index a83cf3f5..113e9777 100644 --- a/rust/candid_derive/src/derive.rs +++ b/rust/candid_derive/src/derive.rs @@ -17,7 +17,7 @@ pub(crate) fn derive_idl_type( let (ty_body, ser_body) = match input.data { Data::Enum(ref data) => enum_from_ast(&name, &data.variants, custom_candid_path), Data::Struct(ref data) => { - let (ty, idents, is_bytes) = struct_from_ast(&data.fields, custom_candid_path); + let (ty, idents, is_bytes, _) = struct_from_ast(&data.fields, custom_candid_path); (ty, serialize_struct(&idents, &is_bytes, custom_candid_path)) } Data::Union(_) => unimplemented!("doesn't derive union type"), @@ -37,7 +37,7 @@ pub(crate) fn derive_idl_type( } } }; - //panic!(gen.to_string()); + //panic!("{}", gen.to_string()); gen } @@ -48,6 +48,7 @@ struct Variant { ty: TokenStream, members: Vec, with_bytes: bool, + style: Style, } enum Style { Struct, @@ -55,17 +56,8 @@ enum Style { Unit, } impl Variant { - fn style(&self) -> Style { - if self.members.is_empty() { - return Style::Unit; - }; - match self.members[0] { - Ident::Named(_) => Style::Struct, - Ident::Unnamed(_) => Style::Tuple, - } - } fn to_pattern(&self) -> (TokenStream, Vec) { - match self.style() { + match self.style { Style::Unit => (quote! {}, Vec::new()), Style::Struct => { let id: Vec<_> = self.members.iter().map(|ident| ident.to_token()).collect(); @@ -114,7 +106,7 @@ fn enum_from_ast( ), None => (id.clone(), idl_hash(&id.unraw().to_string())), }; - let (ty, idents, _) = struct_from_ast(&variant.fields, custom_candid_path); + let (ty, idents, _, style) = struct_from_ast(&variant.fields, custom_candid_path); Variant { real_ident: id, renamed_ident, @@ -122,6 +114,7 @@ fn enum_from_ast( ty, members: idents, with_bytes: attrs.with_bytes, + style, } }) .collect(); @@ -203,7 +196,7 @@ fn serialize_struct( fn struct_from_ast( fields: &syn::Fields, custom_candid_path: &Option, -) -> (TokenStream, Vec, Vec) { +) -> (TokenStream, Vec, Vec, Style) { let candid = candid_path(custom_candid_path); match *fields { syn::Fields::Named(ref fields) => { @@ -212,18 +205,20 @@ fn struct_from_ast( quote! { #candid::types::TypeInner::Record(#fs).into() }, idents, is_bytes, + Style::Struct, ) } syn::Fields::Unnamed(ref fields) => { let (fs, idents, is_bytes) = fields_from_ast(&fields.unnamed, custom_candid_path); if idents.len() == 1 { let newtype = derive_type(&fields.unnamed[0].ty, custom_candid_path); - (quote! { #newtype }, idents, is_bytes) + (quote! { #newtype }, idents, is_bytes, Style::Tuple) } else { ( quote! { #candid::types::TypeInner::Record(#fs).into() }, idents, is_bytes, + Style::Tuple, ) } } @@ -231,6 +226,7 @@ fn struct_from_ast( quote! { #candid::types::TypeInner::Null.into() }, Vec::new(), Vec::new(), + Style::Unit, ), } } diff --git a/tools/didc/Cargo.toml b/tools/didc/Cargo.toml index e96a17b9..f1cf5e91 100644 --- a/tools/didc/Cargo.toml +++ b/tools/didc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "didc" -version = "0.3.4" +version = "0.3.5" authors = ["DFINITY Team"] edition = "2021" From 3535690f7712bc5c9932d74238d3bb4b7bab379f Mon Sep 17 00:00:00 2001 From: Yan Chen Date: Tue, 5 Sep 2023 21:12:46 -0700 Subject: [PATCH 7/7] changelog --- Changelog.md | 12 +++++++++++- README.md | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 5e4c280c..ba3d8baf 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,11 +1,21 @@ # Changelog -## 2023-07-25 (Rust 0.9.2) +## 2023-09-05 (Rust 0.9.6) + +* Improve Rust binding generation: 1) Fix generated code for agent; 2) Generated names conform to Rust convention: Pascal case for type names and enum tags; snake case for function names. +* Fix a bug when deriving empty struct/tuple enum tag, e.g., `#[derive(CandidType)] enum T { A{}, B() }`. +* Add `IDLDeserialize::new_with_config` to control deserializer behavior. For now, you can only bound the size of zero sized values. + +## 2023-07-25 (Rust 0.9.2--0.9.5) * Fix error message for `subtype::equal` to report the correct missing label. * Recover subtype error from custom deserializer. This fixes some custom types for not applying special opt rule. * Fix Candid UI to support composite query. +* Internally, move away from `BigInt::try_into` to allow more build targets, e.g. WASI and iOS. +* Spec change: allow `record {} <: record {null}`. +* Fix length counting of zero sized values. +* Remove `arc_type` feature. ## 2023-07-11 diff --git a/README.md b/README.md index 00c4a8a7..fb295c8d 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ A list of community maintained Candid libraries: * [Motoko](https://github.com/edjcase/motoko_candid) * [C#](https://github.com/edjCase/ICP.NET/tree/main/src/Candid) * [C++](https://github.com/icppWorld/icpp-candid) +* [Python](https://github.com/rocklabs-io/ic-py) ## Tools