From 258b6b6466a00d59d51dc9463a4f7f0d887f32ca Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Tue, 25 Jun 2024 13:56:47 -0700 Subject: [PATCH 1/6] add new links in README (#561) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 435c9353..955c0f0b 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,8 @@ A list of community maintained Candid libraries: * [didc](tools/didc): Candid CLI. Download [prebuilt binary](https://github.com/dfinity/candid/releases). * [ui](tools/ui): Candid UI canister. See deployed [canister](https://a4gq6-oaaaa-aaaab-qaa4q-cai.raw.ic0.app/) on the IC * [ic-repl](https://github.com/chenyan2002/ic-repl): A REPL environment to communicate with canisters using Candid +* [Explain Candid](https://fxa77-fiaaa-aaaae-aaana-cai.raw.icp0.io/explain): An online tool that decodes and explains a given Candid message. (Thanks to Ben Lynn) +* [Candid playground](https://sehgq-cqaaa-aaaap-ahc4q-cai.icp0.io/playground): A playground that generates UI dynamically as you type in the Candid definitions. (Thanks to B3Forge) ## Tests From af33ed8763151aeadebcf63c8a6c9d9736c144cc Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Tue, 25 Jun 2024 14:03:37 -0700 Subject: [PATCH 2/6] more rust bindgen (#560) * make configs public * fix newtype visibility * add variant.std::record::Record.use_type is rename Result type * report unused * no test annotation * fix * bump version * embed metadata * remove unused types in metadata * tests --- Cargo.lock | 3 +- Cargo.toml | 1 + rust/candid_parser/Cargo.toml | 6 +- rust/candid_parser/src/bindings/rust.rs | 80 +++++++++++++------ rust/candid_parser/src/bindings/rust_stub.hbs | 4 + rust/candid_parser/src/configs.rs | 2 +- rust/candid_parser/src/utils.rs | 19 ++++- rust/candid_parser/tests/assets/class.did | 3 +- rust/candid_parser/tests/assets/example.toml | 4 +- rust/candid_parser/tests/assets/ok/actor.rs | 2 +- rust/candid_parser/tests/assets/ok/class.d.ts | 1 + rust/candid_parser/tests/assets/ok/class.did | 3 +- rust/candid_parser/tests/assets/ok/class.js | 4 +- rust/candid_parser/tests/assets/ok/class.mo | 3 +- rust/candid_parser/tests/assets/ok/class.rs | 29 ++++--- rust/candid_parser/tests/assets/ok/cyclic.rs | 2 +- rust/candid_parser/tests/assets/ok/example.rs | 18 ++--- rust/candid_parser/tests/assets/ok/keyword.rs | 6 +- .../tests/assets/ok/recursion.rs | 6 +- rust/candid_parser/tests/parse_type.rs | 6 +- tools/didc/Cargo.toml | 1 + tools/didc/src/main.rs | 18 ++++- 22 files changed, 150 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 832aa886..30cb49fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -216,7 +216,7 @@ dependencies = [ [[package]] name = "candid_parser" -version = "0.2.0-beta.2" +version = "0.2.0-beta.3" dependencies = [ "anyhow", "arbitrary", @@ -414,6 +414,7 @@ dependencies = [ "anyhow", "candid_parser", "clap", + "console", "hex", "pretty-hex", "rand", diff --git a/Cargo.toml b/Cargo.toml index 574ad071..341dbdde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,4 @@ thiserror = "1.0" anyhow = "1.0" rand = "0.8" arbitrary = "1.3" +console = "0.15" diff --git a/rust/candid_parser/Cargo.toml b/rust/candid_parser/Cargo.toml index ecf6052c..4961df50 100644 --- a/rust/candid_parser/Cargo.toml +++ b/rust/candid_parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid_parser" -version = "0.2.0-beta.2" +version = "0.2.0-beta.3" edition = "2021" rust-version.workspace = true authors = ["DFINITY Team"] @@ -33,7 +33,6 @@ logos = "0.14" convert_case = "0.6" handlebars = "5.1" toml = { version = "0.8", default-features = false, features = ["parse"] } -console = "0.15" arbitrary = { workspace = true, optional = true } fake = { version = "2.4", optional = true } @@ -41,6 +40,7 @@ rand = { version = "0.8", optional = true } num-traits = { workspace = true, optional = true } dialoguer = { version = "0.11", default-features = false, features = ["editor", "completion"], optional = true } ctrlc = { version = "3.4", optional = true } +console = { workspace = true, optional = true } [dev-dependencies] goldenfile = "1.1.0" @@ -49,7 +49,7 @@ rand.workspace = true [features] random = ["dep:arbitrary", "dep:fake", "dep:rand", "dep:num-traits"] -assist = ["dep:dialoguer", "dep:ctrlc"] +assist = ["dep:dialoguer", "dep:console", "dep:ctrlc"] all = ["random", "assist"] # docs.rs-specific configuration diff --git a/rust/candid_parser/src/bindings/rust.rs b/rust/candid_parser/src/bindings/rust.rs index 481b05f9..8c8462eb 100644 --- a/rust/candid_parser/src/bindings/rust.rs +++ b/rust/candid_parser/src/bindings/rust.rs @@ -5,7 +5,6 @@ use crate::{ }; use candid::pretty::utils::*; use candid::types::{Field, Function, Label, SharedLabel, Type, TypeEnv, TypeInner}; -use console::style; use convert_case::{Case, Casing}; use pretty::RcDoc; use serde::Serialize; @@ -102,6 +101,13 @@ fn as_result(fs: &[Field]) -> Option<(&Type, &Type)> { _ => None, } } +fn parse_use_type(input: &str) -> (String, bool) { + if let Some((t, "")) = input.rsplit_once("(no test)") { + (t.trim_end().to_string(), false) + } else { + (input.to_string(), true) + } +} static KEYWORDS: [&str; 51] = [ "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return", @@ -176,8 +182,11 @@ fn test_{test_name}() {{ let elem = StateElem::Type(ty); let old = self.state.push_state(&elem); let res = if let Some(t) = &self.state.config.use_type { - let res = RcDoc::text(t.clone()); - self.generate_test(ty, &t.clone()); + let (t, need_test) = parse_use_type(t); + if need_test { + self.generate_test(ty, &t); + } + let res = RcDoc::text(t); self.state.update_stats("use_type"); res } else { @@ -222,11 +231,28 @@ fn test_{test_name}() {{ Variant(ref fs) => { // only possible for result variant let (ok, err) = as_result(fs).unwrap(); - let body = self - .pp_ty(ok, is_ref) - .append(", ") - .append(self.pp_ty(err, is_ref)); - str("std::result::Result").append(enclose("<", body, ">")) + // This is a hacky way to redirect Result type + let old = self + .state + .push_state(&StateElem::TypeStr("std::result::Result")); + let result = if let Some(t) = &self.state.config.use_type { + let (res, _) = parse_use_type(t); + // not generating test for this use_type. rustc should be able to catch type mismatches. + self.state.update_stats("use_type"); + res + } else { + "std::result::Result".to_string() + }; + self.state + .pop_state(old, StateElem::TypeStr("std::result::Result")); + let old = self.state.push_state(&StateElem::Label("Ok")); + let ok = self.pp_ty(ok, is_ref); + self.state.pop_state(old, StateElem::Label("Ok")); + let old = self.state.push_state(&StateElem::Label("Err")); + let err = self.pp_ty(err, is_ref); + self.state.pop_state(old, StateElem::Label("Err")); + let body = ok.append(", ").append(err); + RcDoc::text(result).append(enclose("<", body, ">")) } Func(_) => unreachable!(), // not possible after rewriting Service(_) => unreachable!(), // not possible after rewriting @@ -305,9 +331,13 @@ fn test_{test_name}() {{ res } fn pp_record_fields<'b>(&mut self, fs: &'b [Field], need_vis: bool, is_ref: bool) -> RcDoc<'b> { - let old = self.state.push_state(&StateElem::TypeStr("record")); + let old = if self.state.path.last() == Some(&"record".to_string()) { + // don't push record again when coming from pp_ty + None + } else { + Some(self.state.push_state(&StateElem::TypeStr("record"))) + }; let res = if is_tuple(fs) { - // TODO check if there is no name/attr in the label subtree self.pp_tuple(fs, need_vis, is_ref) } else { let fields: Vec<_> = fs @@ -317,7 +347,9 @@ fn test_{test_name}() {{ let fields = concat(fields.into_iter(), ","); enclose_space("{", fields, "}") }; - self.state.pop_state(old, StateElem::TypeStr("record")); + if let Some(old) = old { + self.state.pop_state(old, StateElem::TypeStr("record")); + } res } fn pp_variant_field<'b>(&mut self, field: &'b Field) -> RcDoc<'b> { @@ -421,10 +453,11 @@ fn test_{test_name}() {{ if self.recs.contains(id) { derive .append(RcDoc::line()) - .append(vis) + .append(vis.clone()) .append("struct ") .append(name) - .append(enclose("(", self.pp_ty(ty, false), ")")) + // TODO: Unfortunately, the visibility of the inner newtype is also controlled by var.visibility + .append(enclose("(", vis.append(self.pp_ty(ty, false)), ")")) .append(";") } else { vis.append(kwd("type")) @@ -688,12 +721,18 @@ pub fn compile( tree: &Config, env: &TypeEnv, actor: &Option, - external: ExternalConfig, -) -> String { + mut external: ExternalConfig, +) -> (String, Vec) { let source = match external.0.get("target").map(|s| s.as_str()) { Some("canister_call") | None => Cow::Borrowed(include_str!("rust_call.hbs")), Some("agent") => Cow::Borrowed(include_str!("rust_agent.hbs")), - Some("stub") => Cow::Borrowed(include_str!("rust_stub.hbs")), + Some("stub") => { + let metadata = crate::utils::get_metadata(env, actor); + if let Some(metadata) = metadata { + external.0.insert("metadata".to_string(), metadata); + } + Cow::Borrowed(include_str!("rust_stub.hbs")) + } Some("custom") => { let template = external .0 @@ -704,14 +743,7 @@ pub fn compile( _ => unimplemented!(), }; let (output, unused) = emit_bindgen(tree, env, actor); - for e in unused { - eprintln!( - "{} path {} is unused", - style("WARNING:").red().bold(), - style(e).green() - ); - } - output_handlebar(output, external, &source) + (output_handlebar(output, external, &source), unused) } pub enum TypePath { diff --git a/rust/candid_parser/src/bindings/rust_stub.hbs b/rust/candid_parser/src/bindings/rust_stub.hbs index 32658194..a0cf2c4c 100644 --- a/rust/candid_parser/src/bindings/rust_stub.hbs +++ b/rust/candid_parser/src/bindings/rust_stub.hbs @@ -19,3 +19,7 @@ fn {{this.name}}({{#each this.args}}{{#if (not @first)}}, {{/if}}{{this.0}}: {{t {{#if tests}} {{tests}} {{/if}} +{{#if metadata}} +#[link_section = "icp:public candid:service"] +pub static __SERVICE: [u8; {{len metadata}}] = *br#"{{metadata}}"#; +{{/if}} diff --git a/rust/candid_parser/src/configs.rs b/rust/candid_parser/src/configs.rs index f6a50d94..c2880f2e 100644 --- a/rust/candid_parser/src/configs.rs +++ b/rust/candid_parser/src/configs.rs @@ -299,7 +299,7 @@ impl ConfigTree { } } #[derive(Clone)] -pub struct Configs(Table); +pub struct Configs(pub Table); impl Configs { pub fn get_subtable(&self, path: &[String]) -> Option<&Table> { let mut res = &self.0; diff --git a/rust/candid_parser/src/utils.rs b/rust/candid_parser/src/utils.rs index f3027180..f465a756 100644 --- a/rust/candid_parser/src/utils.rs +++ b/rust/candid_parser/src/utils.rs @@ -1,4 +1,5 @@ use crate::{check_prog, pretty_check_file, pretty_parse, Error, Result}; +use candid::types::TypeInner; use candid::{types::Type, TypeEnv}; use std::path::Path; @@ -49,7 +50,6 @@ pub fn service_equal(left: CandidSource, right: CandidSource) -> Result<()> { /// If the original did file contains imports, the output flattens the type definitions. /// For now, the comments from the original did file is omitted. pub fn instantiate_candid(candid: CandidSource) -> Result<(Vec, (TypeEnv, Type))> { - use candid::types::TypeInner; let (env, serv) = candid.load()?; let serv = serv.ok_or_else(|| Error::msg("the Candid interface has no main service type"))?; let serv = env.trace_type(&serv)?; @@ -59,6 +59,23 @@ pub fn instantiate_candid(candid: CandidSource) -> Result<(Vec, (TypeEnv, _ => unreachable!(), }) } +pub fn get_metadata(env: &TypeEnv, serv: &Option) -> Option { + let serv = serv.clone()?; + let serv = env.trace_type(&serv).ok()?; + let serv = match serv.as_ref() { + TypeInner::Class(_, ty) => ty.clone(), + TypeInner::Service(_) => serv, + _ => unreachable!(), + }; + let def_list = crate::bindings::analysis::chase_actor(env, &serv).ok()?; + let mut filtered = TypeEnv::new(); + for d in def_list { + if let Some(t) = env.0.get(d) { + filtered.0.insert(d.to_string(), t.clone()); + } + } + Some(candid::pretty::candid::compile(&filtered, &Some(serv))) +} /// Merge canister metadata candid:args and candid:service into a service constructor. /// If candid:service already contains init args, returns the original did file. diff --git a/rust/candid_parser/tests/assets/class.did b/rust/candid_parser/tests/assets/class.did index 326a0520..662461b1 100644 --- a/rust/candid_parser/tests/assets/class.did +++ b/rust/candid_parser/tests/assets/class.did @@ -1,5 +1,6 @@ +type Profile = record { age: nat8; name: text }; type List = opt record { int; List }; -service : (int, List) -> { +service : (int, List, Profile) -> { get : () -> (List); set : (List) -> (List); } diff --git a/rust/candid_parser/tests/assets/example.toml b/rust/candid_parser/tests/assets/example.toml index 8f09274f..92156e9c 100644 --- a/rust/candid_parser/tests/assets/example.toml +++ b/rust/candid_parser/tests/assets/example.toml @@ -6,7 +6,9 @@ Nested41.variant.A = { name = "AAA", attributes = "#[serde(skip_deserializing)]" ListInner.attributes = "#derive[CandidType, Deserialize, Clone]" ListInner.record = { visibility = "", head.name = "HEAD", attributes = "#[serde(skip_deserializing)]", tail.use_type = "Arc" } my_type = { visibility = "", name = "CanisterId" } -nat.use_type = "u128" +nat.use_type = "u128 (no test)" BrokerFindRet = { name = "BrokerReturn", visibility = "pub" } g1 = { name = "G11", arg0.name = "id", arg1.name = "list", arg2.name = "is_okay", ret0.use_type = "i128" } x.ret2.variant.Err.variant.name = "Error" +nested_res.variant.Ok.variant."std::result::Result".use_type = "my::Result" +nested_res.variant.Err.variant."std::result::Result".use_type = "another::Result" diff --git a/rust/candid_parser/tests/assets/ok/actor.rs b/rust/candid_parser/tests/assets/ok/actor.rs index d9d385ec..7049c0a4 100644 --- a/rust/candid_parser/tests/assets/ok/actor.rs +++ b/rust/candid_parser/tests/assets/ok/actor.rs @@ -8,7 +8,7 @@ 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(pub Option>); pub struct Service(pub Principal); impl Service { diff --git a/rust/candid_parser/tests/assets/ok/class.d.ts b/rust/candid_parser/tests/assets/ok/class.d.ts index 5cbc5acb..412ee851 100644 --- a/rust/candid_parser/tests/assets/ok/class.d.ts +++ b/rust/candid_parser/tests/assets/ok/class.d.ts @@ -3,6 +3,7 @@ import type { ActorMethod } from '@dfinity/agent'; import type { IDL } from '@dfinity/candid'; export type List = [] | [[bigint, List]]; +export interface Profile { 'age' : number, 'name' : string } export interface _SERVICE { 'get' : ActorMethod<[], List>, 'set' : ActorMethod<[List], List>, diff --git a/rust/candid_parser/tests/assets/ok/class.did b/rust/candid_parser/tests/assets/ok/class.did index d2ffe0f6..a4749756 100644 --- a/rust/candid_parser/tests/assets/ok/class.did +++ b/rust/candid_parser/tests/assets/ok/class.did @@ -1,2 +1,3 @@ type List = opt record { int; List }; -service : (int, List) -> { get : () -> (List); set : (List) -> (List) } +type Profile = record { age : nat8; name : text }; +service : (int, List, Profile) -> { get : () -> (List); set : (List) -> (List) } diff --git a/rust/candid_parser/tests/assets/ok/class.js b/rust/candid_parser/tests/assets/ok/class.js index 93e6cfdd..5f052ee0 100644 --- a/rust/candid_parser/tests/assets/ok/class.js +++ b/rust/candid_parser/tests/assets/ok/class.js @@ -1,6 +1,7 @@ export const idlFactory = ({ IDL }) => { const List = IDL.Rec(); List.fill(IDL.Opt(IDL.Tuple(IDL.Int, List))); + const Profile = IDL.Record({ 'age' : IDL.Nat8, 'name' : IDL.Text }); return IDL.Service({ 'get' : IDL.Func([], [List], []), 'set' : IDL.Func([List], [List], []), @@ -9,5 +10,6 @@ export const idlFactory = ({ IDL }) => { export const init = ({ IDL }) => { const List = IDL.Rec(); List.fill(IDL.Opt(IDL.Tuple(IDL.Int, List))); - return [IDL.Int, List]; + const Profile = IDL.Record({ 'age' : IDL.Nat8, 'name' : IDL.Text }); + return [IDL.Int, List, Profile]; }; diff --git a/rust/candid_parser/tests/assets/ok/class.mo b/rust/candid_parser/tests/assets/ok/class.mo index 1a62c956..ad5666f4 100644 --- a/rust/candid_parser/tests/assets/ok/class.mo +++ b/rust/candid_parser/tests/assets/ok/class.mo @@ -3,7 +3,8 @@ module { public type List = ?(Int, List); - public type Self = (Int, List) -> async actor { + public type Profile = { age : Nat8; name : Text }; + public type Self = (Int, List, Profile) -> async actor { get : shared () -> async List; set : shared List -> async List; } diff --git a/rust/candid_parser/tests/assets/ok/class.rs b/rust/candid_parser/tests/assets/ok/class.rs index cfed8194..ecb1b190 100644 --- a/rust/candid_parser/tests/assets/ok/class.rs +++ b/rust/candid_parser/tests/assets/ok/class.rs @@ -2,20 +2,25 @@ // You may want to manually adjust some of the types. #![allow(dead_code, unused_imports)] use candid::{self, CandidType, Deserialize, Principal}; -use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] -pub struct List(Option<(candid::Int,Box,)>); +pub struct List(pub Option<(candid::Int,Box,)>); +#[derive(CandidType, Deserialize)] +pub struct Profile { pub age: u8, pub name: String } -pub struct Service(pub Principal); -impl Service { - pub async fn get(&self) -> Result<(List,)> { - ic_cdk::call(self.0, "get", ()).await - } - pub async fn set(&self, arg0: List) -> Result<(List,)> { - ic_cdk::call(self.0, "set", (arg0,)).await - } +#[ic_cdk::init] +fn init(arg0: candid::Int, arg1: List, arg2: Profile) { + unimplemented!() +} +#[ic_cdk::update] +fn get() -> List { + unimplemented!() +} +#[ic_cdk::update] +fn set(arg0: List) -> List { + unimplemented!() } -pub const CANISTER_ID : Principal = Principal::from_slice(&[]); // aaaaa-aa -pub const service : Service = Service(CANISTER_ID); +#[link_section = "icp:public candid:service"] +pub static __SERVICE: [u8; 94] = *br#"type List = opt record { int; List }; +service : { get : () -> (List); set : (List) -> (List) }"#; diff --git a/rust/candid_parser/tests/assets/ok/cyclic.rs b/rust/candid_parser/tests/assets/ok/cyclic.rs index 314286e9..a7186883 100644 --- a/rust/candid_parser/tests/assets/ok/cyclic.rs +++ b/rust/candid_parser/tests/assets/ok/cyclic.rs @@ -7,7 +7,7 @@ use ic_cdk::api::call::CallResult as Result; pub type C = Box; pub type B = Option; #[derive(CandidType, Deserialize)] -pub struct A(Option); +pub struct A(pub Option); pub type Z = Box; pub type Y = Z; pub type X = Y; diff --git a/rust/candid_parser/tests/assets/ok/example.rs b/rust/candid_parser/tests/assets/ok/example.rs index 73d307fd..dac11e1d 100644 --- a/rust/candid_parser/tests/assets/ok/example.rs +++ b/rust/candid_parser/tests/assets/ok/example.rs @@ -9,10 +9,10 @@ pub(crate) struct B (pub(crate) candid::Int,pub(crate) u128,); #[derive(CandidType, Deserialize, Debug)] pub(crate) struct Node { pub(crate) head: u128, pub(crate) tail: Box } #[derive(CandidType, Deserialize, Debug)] -pub(crate) struct List(Option); +pub(crate) struct List(pub(crate) Option); pub(crate) type A = Box; #[derive(CandidType, Deserialize, Debug)] -pub(crate) struct B(Option); +pub(crate) struct B(pub(crate) Option); #[derive(CandidType, Deserialize, Debug)] pub(crate) enum Tree { #[serde(rename="branch")] @@ -27,7 +27,7 @@ pub(crate) struct StreamInner { pub(crate) next: StreamInnerNext, } #[derive(CandidType, Deserialize, Debug)] -pub(crate) struct Stream(Option); +pub(crate) struct Stream(pub(crate) Option); candid::define_service!(pub(crate) S : { "f" : T::ty(); "g" : candid::func!((List) -> (B, Tree, Stream)); @@ -43,7 +43,7 @@ pub(crate) struct ListInner { tail: Arc, } #[derive(CandidType, Deserialize, Debug)] -pub(crate) struct MyList(Option); +pub(crate) struct MyList(pub(crate) Option); #[derive(CandidType, Deserialize, Debug)] pub(crate) struct Nested3 { pub(crate) _0_: u128, @@ -79,9 +79,7 @@ candid::define_service!(pub(crate) Broker : { #[derive(CandidType, Deserialize, Debug)] pub(crate) struct NestedResErrOk { pub(crate) content: String } pub(crate) type NestedRes = std::result::Result< - std::result::Result<(), ()>, std::result::Result< - NestedResErrOk, (candid::Int,) - > + my::Result<(), ()>, another::Result >; #[derive(CandidType, Deserialize, Debug)] pub(crate) enum HArg1 { A(u128), B(Option) } @@ -147,10 +145,4 @@ fn test_i128() { let candid_src = r#"(int)"#; candid_parser::utils::check_rust_type::(candid_src).unwrap(); } -#[test] -fn test_u128() { - // Generated from nat.use_type = "u128" - let candid_src = r#"(nat)"#; - candid_parser::utils::check_rust_type::(candid_src).unwrap(); -} diff --git a/rust/candid_parser/tests/assets/ok/keyword.rs b/rust/candid_parser/tests/assets/ok/keyword.rs index f50de12e..ae002bb1 100644 --- a/rust/candid_parser/tests/assets/ok/keyword.rs +++ b/rust/candid_parser/tests/assets/ok/keyword.rs @@ -5,7 +5,7 @@ use candid::{self, CandidType, Deserialize, Principal}; use ic_cdk::api::call::CallResult as Result; #[derive(CandidType, Deserialize)] -pub struct O(Option>); +pub struct O(pub Option>); #[derive(CandidType, Deserialize)] pub struct FieldArg { pub test: u16, pub _1291438163_: u8 } #[derive(CandidType, Deserialize)] @@ -19,7 +19,7 @@ pub struct FieldnatArg { #[derive(CandidType, Deserialize)] pub struct Node { pub head: candid::Nat, pub tail: Box } #[derive(CandidType, Deserialize)] -pub struct List(Option); +pub struct List(pub Option); #[derive(CandidType, Deserialize)] pub enum If { #[serde(rename="branch")] @@ -31,7 +31,7 @@ candid::define_function!(pub StreamInnerNext : () -> (Stream) query); #[derive(CandidType, Deserialize)] pub struct StreamInner { pub head: candid::Nat, pub next: StreamInnerNext } #[derive(CandidType, Deserialize)] -pub struct Stream(Option); +pub struct Stream(pub Option); candid::define_service!(pub Return : { "f" : T::ty(); "g" : candid::func!((List) -> (If, Stream)); diff --git a/rust/candid_parser/tests/assets/ok/recursion.rs b/rust/candid_parser/tests/assets/ok/recursion.rs index 91aca069..480962c7 100644 --- a/rust/candid_parser/tests/assets/ok/recursion.rs +++ b/rust/candid_parser/tests/assets/ok/recursion.rs @@ -8,10 +8,10 @@ candid::define_function!(pub T : (S) -> ()); #[derive(CandidType, Deserialize)] pub struct Node { pub head: candid::Nat, pub tail: Box } #[derive(CandidType, Deserialize)] -pub struct List(Option); +pub struct List(pub Option); pub type A = Box; #[derive(CandidType, Deserialize)] -pub struct B(Option); +pub struct B(pub Option); #[derive(CandidType, Deserialize)] pub enum Tree { #[serde(rename="branch")] @@ -23,7 +23,7 @@ candid::define_function!(pub StreamInnerNext : () -> (Stream) query); #[derive(CandidType, Deserialize)] pub struct StreamInner { pub head: candid::Nat, pub next: StreamInnerNext } #[derive(CandidType, Deserialize)] -pub struct Stream(Option); +pub struct Stream(pub Option); candid::define_service!(pub S : { "f" : T::ty(); "g" : candid::func!((List) -> (B, Tree, Stream)); diff --git a/rust/candid_parser/tests/parse_type.rs b/rust/candid_parser/tests/parse_type.rs index 2d7bb219..ad956940 100644 --- a/rust/candid_parser/tests/parse_type.rs +++ b/rust/candid_parser/tests/parse_type.rs @@ -74,6 +74,9 @@ fn compiler_test(resource: &str) { "management.did" => { drop(external.0.insert("target".to_string(), "agent".to_string())) } + "class.did" => { + drop(external.0.insert("target".to_string(), "stub".to_string())) + } "example.did" => { let configs = std::fs::read_to_string(base_path.join("example.toml")) .unwrap() @@ -84,7 +87,8 @@ fn compiler_test(resource: &str) { _ => (), } let mut output = mint.new_goldenfile(filename.with_extension("rs")).unwrap(); - let content = rust::compile(&config, &env, &actor, external); + let (content, unused) = rust::compile(&config, &env, &actor, external); + assert!(unused.is_empty()); writeln!(output, "{content}").unwrap(); } { diff --git a/tools/didc/Cargo.toml b/tools/didc/Cargo.toml index 7243aa19..d6a61b46 100644 --- a/tools/didc/Cargo.toml +++ b/tools/didc/Cargo.toml @@ -11,4 +11,5 @@ pretty-hex = "0.2.1" hex.workspace = true anyhow.workspace = true rand.workspace = true +console.workspace = true diff --git a/tools/didc/src/main.rs b/tools/didc/src/main.rs index d6db3b70..bed24ab0 100644 --- a/tools/didc/src/main.rs +++ b/tools/didc/src/main.rs @@ -8,6 +8,7 @@ use candid_parser::{ Error, IDLArgs, IDLValue, TypeEnv, }; use clap::Parser; +use console::style; use std::collections::HashSet; use std::io; use std::path::PathBuf; @@ -169,6 +170,15 @@ fn load_config(input: &Option) -> Result { Some(str) => Configs::from_str(str), } } +fn warn_unused(unused: &[String]) { + for e in unused { + eprintln!( + "{} path {} is unused.", + style("WARNING:").red().bold(), + style(e).green(), + ); + } +} fn main() -> Result<()> { match Command::parse() { @@ -229,7 +239,9 @@ fn main() -> Result<()> { .map(|x| x.clone().try_into().unwrap()) .unwrap_or(ExternalConfig::default()); let config = Config::new(configs); - compile(&config, &env, &actor, external) + let (res, unused) = compile(&config, &env, &actor, external); + warn_unused(&unused); + res } "rs-agent" | "rs-stub" => { use candid_parser::bindings::rust::{compile, Config, ExternalConfig}; @@ -241,7 +253,9 @@ fn main() -> Result<()> { _ => unreachable!(), }; external.0.insert("target".to_string(), target.to_string()); - compile(&config, &env, &actor, external) + let (res, unused) = compile(&config, &env, &actor, external); + warn_unused(&unused); + res } _ => unreachable!(), }; From cccaa04668e992300135960c1bc35401c050f4d0 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:19:50 -0700 Subject: [PATCH 3/6] fix test suite (#564) * fix test suite * fix * fix * fix * Apply suggestions from code review Co-authored-by: Claudio Russo --------- Co-authored-by: Claudio Russo --- test/spacebomb.test.did | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/spacebomb.test.did b/test/spacebomb.test.did index fed3a2da..1c611046 100644 --- a/test/spacebomb.test.did +++ b/test/spacebomb.test.did @@ -16,22 +16,22 @@ // Plain decoding (unused arguments) assert blob "DIDL\01\6d\7f\01\00\80\94\eb\dc\03" !: () "vec null (extra argument)"; assert blob "DIDL\01\6d\70\01\00\80\94\eb\dc\03" !: () "vec reserved (extra argument)"; -assert blob "DIDL\04\6c\03\01\7f\02\01\03\02\6c\01\01\70\6c\00\6d\00\01\03\80\94\eb\dc\03" !: () "zero-sized record (extra argument)"; +assert blob "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\80\94\eb\dc\03" !: () "zero-sized record (extra argument)"; assert blob "DIDL\02\6d\01\6d\7f\01\00\05\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f" !: () "vec vec null (extra argument)"; -assert blob "DIDL\03\6c\01\d6\fc\a7\02\01\6d\02\6c\00\01\00\80\ad\e2\04" !: () "vec record {} (extra argument)"; +assert blob "DIDL\02\6d\01\6c\00\01\00\80\ad\e2\04" !: () "vec record {} (extra argument)"; assert blob "DIDL\17\6c\02\01\7f\02\7f\6c\02\01\00\02\00\6c\02\00\01\01\01\6c\02\00\02\01\02\6c\02\00\03\01\03\6c\02\00\04\01\04\6c\02\00\05\01\05\6c\02\00\06\01\06\6c\02\00\07\01\07\6c\02\00\08\01\08\6c\02\00\09\01\09\6c\02\00\0a\01\0a\6c\02\00\0b\01\0b\6c\02\00\0c\01\0c\6c\02\00\0d\02\0d\6c\02\00\0e\01\0e\6c\02\00\0f\01\0f\6c\02\00\10\01\10\6c\02\00\11\01\11\6c\02\00\12\01\12\6c\02\00\13\01\13\6e\14\6d\15\01\16\02\01\01" !: () "vec opt record with 2^20 null (extra argument)"; // Decoding to actual type assert blob "DIDL\01\6d\7f\01\00\80\94\eb\dc\03" !: (vec opt nat) "vec null (not ignored)"; assert blob "DIDL\01\6d\70\01\00\80\94\eb\dc\03" !: (vec reserved) "vec reserved (not ignored)"; -assert blob "DIDL\04\6c\03\01\7f\02\01\03\02\6c\01\01\70\6c\00\6d\00\01\03\80\94\eb\dc\03" !: (vec record {null;record{reserved};record{}}) "zero-sized record (not ignored)"; +assert blob "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\80\94\eb\dc\03" !: (vec record {null;record{reserved};record{}}) "zero-sized record (not ignored)"; assert blob "DIDL\02\6d\01\6d\7f\01\00\05\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f" !: (vec vec null) "vec vec null (not ignored)"; -assert blob "DIDL\03\6c\01\d6\fc\a7\02\01\6d\02\6c\00\01\00\80\ad\e2\04" !: (vec record {}) "vec record {} (not ignored)"; +assert blob "DIDL\02\6d\01\6c\00\01\00\80\ad\e2\04" !: (vec record {}) "vec record {} (not ignored)"; // Decoding under opt assert blob "DIDL\01\6d\7f\01\00\80\94\eb\dc\03" !: (opt nat) "vec null (subtyping)"; assert blob "DIDL\01\6d\70\01\00\80\94\eb\dc\03" !: (opt nat) "vec reserved (subtyping)"; -assert blob "DIDL\04\6c\03\01\7f\02\01\03\02\6c\01\01\70\6c\00\6d\00\01\03\80\94\eb\dc\03" !: (opt nat) "zero-sized record (subtyping)"; +assert blob "DIDL\04\6c\03\00\7f\01\01\02\02\6c\01\00\70\6c\00\6d\00\01\03\80\94\eb\dc\03" !: (opt nat) "zero-sized record (subtyping)"; assert blob "DIDL\02\6d\01\6d\7f\01\00\05\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f\ff\ff\3f" !: (vec opt nat) "vec vec null (subtyping)"; -assert blob "DIDL\03\6c\01\d6\fc\a7\02\01\6d\02\6c\00\01\00\80\ad\e2\04" !: (opt nat) "vec record {} (subtyping)"; +assert blob "DIDL\02\6d\01\6c\00\01\00\80\ad\e2\04" !: (opt nat) "vec record {} (subtyping)"; assert blob "DIDL\17\6c\02\01\7f\02\7f\6c\02\01\00\02\00\6c\02\00\01\01\01\6c\02\00\02\01\02\6c\02\00\03\01\03\6c\02\00\04\01\04\6c\02\00\05\01\05\6c\02\00\06\01\06\6c\02\00\07\01\07\6c\02\00\08\01\08\6c\02\00\09\01\09\6c\02\00\0a\01\0a\6c\02\00\0b\01\0b\6c\02\00\0c\01\0c\6c\02\00\0d\02\0d\6c\02\00\0e\01\0e\6c\02\00\0f\01\0f\6c\02\00\10\01\10\6c\02\00\11\01\11\6c\02\00\12\01\12\6c\02\00\13\01\13\6e\14\6d\15\01\16\05\01\01\01\01\01" !: (vec opt record {}) "vec opt record with 2^20 null (subtyping)"; From 47f6cae26f60c642bda8df2f047e5fd8f0a9e9c1 Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:13:11 -0700 Subject: [PATCH 4/6] More rust bindgen fix (#562) * project_methods fail on not found * snake case for record fields * add MotokoResult * change template to take reference for call * bump dependencies --- Cargo.lock | 247 +++++++++--------- Changelog.md | 4 + rust/candid/Cargo.toml | 2 +- rust/candid/src/lib.rs | 1 + rust/candid/src/types/mod.rs | 1 + rust/candid/src/types/result.rs | 60 +++++ rust/candid_parser/Cargo.toml | 4 +- rust/candid_parser/src/bindings/analysis.rs | 30 ++- rust/candid_parser/src/bindings/rust.rs | 22 +- .../candid_parser/src/bindings/rust_agent.hbs | 2 +- rust/candid_parser/src/bindings/rust_call.hbs | 2 +- rust/candid_parser/tests/assets/ok/actor.rs | 8 +- rust/candid_parser/tests/assets/ok/cyclic.rs | 2 +- rust/candid_parser/tests/assets/ok/empty.rs | 6 +- rust/candid_parser/tests/assets/ok/escape.rs | 2 +- rust/candid_parser/tests/assets/ok/example.rs | 16 +- .../candid_parser/tests/assets/ok/fieldnat.rs | 14 +- rust/candid_parser/tests/assets/ok/keyword.rs | 20 +- .../tests/assets/ok/management.rs | 36 +-- .../tests/assets/ok/recursion.rs | 4 +- rust/candid_parser/tests/assets/ok/unicode.rs | 6 +- tools/didc/Cargo.toml | 2 +- tools/didc/src/main.rs | 4 +- 23 files changed, 296 insertions(+), 199 deletions(-) create mode 100644 rust/candid/src/types/result.rs diff --git a/Cargo.lock b/Cargo.lock index 30cb49fe..7e5c9381 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -28,33 +28,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys", @@ -126,7 +126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" dependencies = [ "either", - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", "syn 1.0.109", ] @@ -148,9 +148,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -163,13 +163,13 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.17" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ - "lazy_static", "memchr", - "regex-automata 0.1.10", + "regex-automata", + "serde", ] [[package]] @@ -180,7 +180,7 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "candid" -version = "0.10.9" +version = "0.10.10" dependencies = [ "anyhow", "bincode", @@ -209,14 +209,14 @@ name = "candid_derive" version = "0.6.6" dependencies = [ "lazy_static", - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "candid_parser" -version = "0.2.0-beta.3" +version = "0.2.0-beta.4" dependencies = [ "anyhow", "arbitrary", @@ -245,9 +245,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.99" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" [[package]] name = "cfg-if" @@ -263,9 +263,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "clap" -version = "4.5.7" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" +checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3" dependencies = [ "clap_builder", "clap_derive", @@ -273,9 +273,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.7" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" +checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa" dependencies = [ "anstream", "anstyle", @@ -285,21 +285,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.5" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" +checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e" dependencies = [ "heck", - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "codespan-reporting" @@ -313,9 +313,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "console" @@ -453,9 +453,9 @@ dependencies = [ [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "ena" @@ -563,9 +563,9 @@ checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "handlebars" -version = "5.1.2" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +checksum = "5226a0e122dc74917f3a701484482bed3ee86d016c7356836abbaa033133a157" dependencies = [ "log", "pest", @@ -627,9 +627,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -674,14 +674,14 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex-automata 0.4.7", + "regex-automata", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "leb128" @@ -723,9 +723,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "logos" @@ -745,10 +745,10 @@ dependencies = [ "beef", "fnv", "lazy_static", - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", "regex-syntax", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -786,9 +786,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -850,9 +850,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pest" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" dependencies = [ "memchr", "thiserror", @@ -861,9 +861,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" dependencies = [ "pest", "pest_generator", @@ -871,22 +871,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "pest_meta" -version = "2.7.10" +version = "2.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" dependencies = [ "once_cell", "pest", @@ -943,9 +943,9 @@ dependencies = [ [[package]] name = "pretty-hex" -version = "0.2.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131" +checksum = "bbc83ee4a840062f368f9096d80077a9841ec117e17e7f700df81958f1451254" [[package]] name = "proc-macro2" @@ -958,9 +958,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -989,7 +989,7 @@ version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", ] [[package]] @@ -1024,9 +1024,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags", ] @@ -1050,16 +1050,10 @@ checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", + "regex-automata", "regex-syntax", ] -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - [[package]] name = "regex-automata" version = "0.4.7" @@ -1119,18 +1113,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] @@ -1147,31 +1141,32 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -1204,9 +1199,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "similar" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" dependencies = [ "bstr", "unicode-segmentation", @@ -1283,18 +1278,18 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.66" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", "unicode-ident", ] @@ -1345,22 +1340,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ - "proc-macro2 1.0.85", + "proc-macro2 1.0.86", "quote 1.0.36", - "syn 2.0.66", + "syn 2.0.72", ] [[package]] @@ -1374,9 +1369,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.14" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +checksum = "81967dd0dd2c1ab0bc3468bd7caecc32b8a4aa47d0c8c695d8c2b2108168d62c" dependencies = [ "serde", "serde_spanned", @@ -1386,18 +1381,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "f8fb9f64314842840f1d940ac544da178732128f1c78c21772e876579e0da1db" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.14" +version = "0.22.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +checksum = "8d9f8729f5aea9562aac1cc0441f5d6de3cff1ee0c5d67293eeca5eb36ee7c16" dependencies = [ "indexmap", "serde", @@ -1462,9 +1457,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" @@ -1524,9 +1519,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1540,57 +1535,57 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.13" +version = "0.6.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +checksum = "b480ae9340fc261e6be3e95a1ba86d54ae3f9171132a73ce8d4bbaf68339507c" dependencies = [ "memchr", ] diff --git a/Changelog.md b/Changelog.md index 0114116f..22ff7790 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,10 @@ ## 2024-05-03 +### Candid 0.10.10 + +* Add `candid::MotokoResult` type. Use `motoko_result.into_result()` to convert the value into Rust result, and `rust_result.into()` to get Motoko result. + ### candid_parser 0.2.0-beta * Breaking changes: diff --git a/rust/candid/Cargo.toml b/rust/candid/Cargo.toml index 326d7bac..3385f1b2 100644 --- a/rust/candid/Cargo.toml +++ b/rust/candid/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid" -version = "0.10.9" +version = "0.10.10" edition = "2021" rust-version.workspace = true authors = ["DFINITY Team"] diff --git a/rust/candid/src/lib.rs b/rust/candid/src/lib.rs index 07bcca22..e83807b4 100644 --- a/rust/candid/src/lib.rs +++ b/rust/candid/src/lib.rs @@ -250,6 +250,7 @@ pub use types::{ rc, reference::{Func, Service}, reserved::{Empty, Reserved}, + result::MotokoResult, TypeEnv, }; diff --git a/rust/candid/src/types/mod.rs b/rust/candid/src/types/mod.rs index aab4554a..49af606d 100644 --- a/rust/candid/src/types/mod.rs +++ b/rust/candid/src/types/mod.rs @@ -25,6 +25,7 @@ pub mod number; pub mod principal; pub mod reference; pub mod reserved; +pub mod result; pub mod arc; pub mod rc; diff --git a/rust/candid/src/types/result.rs b/rust/candid/src/types/result.rs new file mode 100644 index 00000000..70eef1c1 --- /dev/null +++ b/rust/candid/src/types/result.rs @@ -0,0 +1,60 @@ +use crate::types::{CandidType, Compound, Field, Label, Serializer, Type, TypeInner}; +use serde::{Deserialize, Serialize}; + +#[allow(non_camel_case_types)] +#[derive(Deserialize, Debug, Clone, Serialize)] +pub enum MotokoResult { + ok(T), + err(E), +} +impl MotokoResult { + pub fn into_result(self) -> Result { + match self { + MotokoResult::ok(v) => Ok(v), + MotokoResult::err(e) => Err(e), + } + } +} +impl From> for MotokoResult { + fn from(r: Result) -> Self { + match r { + Ok(v) => MotokoResult::ok(v), + Err(e) => MotokoResult::err(e), + } + } +} +impl CandidType for MotokoResult +where + T: CandidType, + E: CandidType, +{ + fn _ty() -> Type { + TypeInner::Variant(vec![ + // Make sure the field id is sorted by idl_hash + Field { + id: Label::Named("ok".to_owned()).into(), + ty: T::ty(), + }, + Field { + id: Label::Named("err".to_owned()).into(), + ty: E::ty(), + }, + ]) + .into() + } + fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> + where + S: Serializer, + { + match *self { + MotokoResult::ok(ref v) => { + let mut ser = serializer.serialize_variant(0)?; + Compound::serialize_element(&mut ser, v) + } + MotokoResult::err(ref e) => { + let mut ser = serializer.serialize_variant(1)?; + Compound::serialize_element(&mut ser, e) + } + } + } +} diff --git a/rust/candid_parser/Cargo.toml b/rust/candid_parser/Cargo.toml index 4961df50..e648989c 100644 --- a/rust/candid_parser/Cargo.toml +++ b/rust/candid_parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "candid_parser" -version = "0.2.0-beta.3" +version = "0.2.0-beta.4" edition = "2021" rust-version.workspace = true authors = ["DFINITY Team"] @@ -31,7 +31,7 @@ serde.workspace = true lalrpop-util = "0.20.0" logos = "0.14" convert_case = "0.6" -handlebars = "5.1" +handlebars = "6.0" toml = { version = "0.8", default-features = false, features = ["parse"] } arbitrary = { workspace = true, optional = true } diff --git a/rust/candid_parser/src/bindings/analysis.rs b/rust/candid_parser/src/bindings/analysis.rs index 8a133a69..edd316bc 100644 --- a/rust/candid_parser/src/bindings/analysis.rs +++ b/rust/candid_parser/src/bindings/analysis.rs @@ -1,16 +1,36 @@ -use crate::Result; +use crate::{Error, Result}; use candid::types::{Type, TypeEnv, TypeInner}; use std::collections::{BTreeMap, BTreeSet}; /// Select a subset of methods from an actor. -pub fn project_methods(env: &TypeEnv, actor: &Option, methods: &[String]) -> Option { - let service = env.as_service(actor.as_ref()?).ok()?; +pub fn project_methods( + env: &TypeEnv, + actor: &Option, + mut methods: Vec, +) -> Result { + let actor = actor + .as_ref() + .ok_or_else(|| Error::Custom(anyhow::anyhow!("no actor")))?; + let service = env.as_service(actor)?; let filtered = service .iter() - .filter(|(name, _)| methods.contains(name)) + .filter(|(name, _)| { + if let Some(idx) = methods.iter().position(|m| m == name) { + methods.swap_remove(idx); + true + } else { + false + } + }) .cloned() .collect(); - Some(TypeInner::Service(filtered).into()) + if !methods.is_empty() { + return Err(Error::Custom(anyhow::anyhow!( + "methods not found: {:?}", + methods + ))); + } + Ok(TypeInner::Service(filtered).into()) } /// Same as chase_actor, with seen set as part of the type. Used for chasing type names from type definitions. diff --git a/rust/candid_parser/src/bindings/rust.rs b/rust/candid_parser/src/bindings/rust.rs index 8c8462eb..ab173079 100644 --- a/rust/candid_parser/src/bindings/rust.rs +++ b/rust/candid_parser/src/bindings/rust.rs @@ -90,13 +90,19 @@ pub(crate) fn is_tuple(fs: &[Field]) -> bool { .enumerate() .any(|(i, field)| field.id.get_id() != (i as u32)) } -fn as_result(fs: &[Field]) -> Option<(&Type, &Type)> { +fn as_result(fs: &[Field]) -> Option<(&Type, &Type, bool)> { match fs { [Field { id: ok, ty: t_ok }, Field { id: err, ty: t_err }] if **ok == Label::Named("Ok".to_string()) && **err == Label::Named("Err".to_string()) => { - Some((t_ok, t_err)) + Some((t_ok, t_err, false)) + } + [Field { id: ok, ty: t_ok }, Field { id: err, ty: t_err }] + if **ok == Label::Named("ok".to_string()) + && **err == Label::Named("err".to_string()) => + { + Some((t_ok, t_err, true)) } _ => None, } @@ -230,7 +236,7 @@ fn test_{test_name}() {{ Record(ref fs) => self.pp_record_fields(fs, false, is_ref), Variant(ref fs) => { // only possible for result variant - let (ok, err) = as_result(fs).unwrap(); + let (ok, err, is_motoko) = as_result(fs).unwrap(); // This is a hacky way to redirect Result type let old = self .state @@ -240,6 +246,8 @@ fn test_{test_name}() {{ // not generating test for this use_type. rustc should be able to catch type mismatches. self.state.update_stats("use_type"); res + } else if is_motoko { + "candid::MotokoResult".to_string() } else { "std::result::Result".to_string() }; @@ -285,7 +293,13 @@ fn test_{test_name}() {{ self.state.update_stats("name"); res } else { - let case = if is_variant { Some(Case::Pascal) } else { None }; + let case = if is_variant { + Some(Case::Pascal) + } else if !id.starts_with('_') { + Some(Case::Snake) + } else { + None + }; ident_(id, case) }; let attr = if is_rename { diff --git a/rust/candid_parser/src/bindings/rust_agent.hbs b/rust/candid_parser/src/bindings/rust_agent.hbs index f4521ae2..4e052625 100644 --- a/rust/candid_parser/src/bindings/rust_agent.hbs +++ b/rust/candid_parser/src/bindings/rust_agent.hbs @@ -9,7 +9,7 @@ type Result = std::result::Result; pub struct {{PascalCase service_name}}<'a>(pub Principal, pub &'a ic_agent::Agent); impl<'a> {{PascalCase service_name}}<'a> { {{#each methods}} - pub async fn {{this.name}}(&self{{#each this.args}}, {{this.0}}: {{this.1}}{{/each}}) -> Result<{{vec_to_arity this.rets}}> { + pub async fn {{this.name}}(&self{{#each this.args}}, {{this.0}}: &{{this.1}}{{/each}}) -> Result<{{vec_to_arity this.rets}}> { let args = Encode!({{#each this.args}}&{{this.0}}{{#unless @last}},{{/unless}}{{/each}})?; let bytes = self.1.{{#if (eq this.mode "update")}}update{{else}}query{{/if}}(&self.0, "{{escape_debug this.original_name}}").with_arg(args).{{#if (eq this.mode "update")}}call_and_wait{{else}}call{{/if}}().await?; Ok(Decode!(&bytes{{#each this.rets}}, {{this}}{{/each}})?) diff --git a/rust/candid_parser/src/bindings/rust_call.hbs b/rust/candid_parser/src/bindings/rust_call.hbs index 55fbf3a9..788fc0db 100644 --- a/rust/candid_parser/src/bindings/rust_call.hbs +++ b/rust/candid_parser/src/bindings/rust_call.hbs @@ -9,7 +9,7 @@ use ic_cdk::api::call::CallResult as Result; pub struct {{PascalCase service_name}}(pub Principal); impl {{PascalCase service_name}} { {{#each methods}} - pub async fn {{this.name}}(&self{{#each this.args}}, {{this.0}}: {{this.1}}{{/each}}) -> Result<({{#each this.rets}}{{this}},{{/each}})> { + pub async fn {{this.name}}(&self{{#each this.args}}, {{this.0}}: &{{this.1}}{{/each}}) -> Result<({{#each this.rets}}{{this}},{{/each}})> { ic_cdk::call(self.0, "{{escape_debug this.original_name}}", ({{#each this.args}}{{this.0}},{{/each}})).await } {{/each}} diff --git a/rust/candid_parser/tests/assets/ok/actor.rs b/rust/candid_parser/tests/assets/ok/actor.rs index 7049c0a4..2b30a305 100644 --- a/rust/candid_parser/tests/assets/ok/actor.rs +++ b/rust/candid_parser/tests/assets/ok/actor.rs @@ -12,16 +12,16 @@ pub struct O(pub 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,)> { + pub async fn g(&self, arg0: &i8) -> Result<(i8,)> { ic_cdk::call(self.0, "g", (arg0,)).await } - pub async fn h(&self, arg0: i8) -> Result<(i8,)> { + 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_parser/tests/assets/ok/cyclic.rs b/rust/candid_parser/tests/assets/ok/cyclic.rs index a7186883..33eaa02f 100644 --- a/rust/candid_parser/tests/assets/ok/cyclic.rs +++ b/rust/candid_parser/tests/assets/ok/cyclic.rs @@ -14,7 +14,7 @@ pub type X = Y; pub struct Service(pub Principal); impl Service { - pub async fn f(&self, arg0: A, arg1: B, arg2: C, arg3: X, arg4: Y, arg5: Z) -> Result<()> { + pub async fn f(&self, arg0: &A, arg1: &B, arg2: &C, arg3: &X, arg4: &Y, arg5: &Z) -> Result<()> { ic_cdk::call(self.0, "f", (arg0,arg1,arg2,arg3,arg4,arg5,)).await } } diff --git a/rust/candid_parser/tests/assets/ok/empty.rs b/rust/candid_parser/tests/assets/ok/empty.rs index 2338c077..4477e9f9 100644 --- a/rust/candid_parser/tests/assets/ok/empty.rs +++ b/rust/candid_parser/tests/assets/ok/empty.rs @@ -17,13 +17,13 @@ pub enum HRet { #[serde(rename="a")] A(Box), #[serde(rename="b")] B{} } pub struct Service(pub Principal); impl Service { - pub async fn f(&self, arg0: FArg) -> Result<(FRet,)> { + pub async fn f(&self, arg0: &FArg) -> Result<(FRet,)> { ic_cdk::call(self.0, "f", (arg0,)).await } - pub async fn g(&self, arg0: T) -> Result<(GRet,)> { + pub async fn g(&self, arg0: &T) -> Result<(GRet,)> { ic_cdk::call(self.0, "g", (arg0,)).await } - pub async fn h(&self, arg0: (T,candid::Empty,)) -> Result<(HRet,)> { + pub async fn h(&self, arg0: &(T,candid::Empty,)) -> Result<(HRet,)> { ic_cdk::call(self.0, "h", (arg0,)).await } } diff --git a/rust/candid_parser/tests/assets/ok/escape.rs b/rust/candid_parser/tests/assets/ok/escape.rs index 776d7e6c..0fde3e5d 100644 --- a/rust/candid_parser/tests/assets/ok/escape.rs +++ b/rust/candid_parser/tests/assets/ok/escape.rs @@ -18,7 +18,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_parser/tests/assets/ok/example.rs b/rust/candid_parser/tests/assets/ok/example.rs index dac11e1d..03559464 100644 --- a/rust/candid_parser/tests/assets/ok/example.rs +++ b/rust/candid_parser/tests/assets/ok/example.rs @@ -104,28 +104,28 @@ pub(crate) enum Error { #[serde(rename="a")] A, #[serde(rename="b")] B } pub struct Service(pub Principal); impl Service { - pub async fn bbbbb(&self, arg0: B) -> Result<()> { + pub async fn bbbbb(&self, arg0: &B) -> Result<()> { ic_cdk::call(self.0, "bbbbb", (arg0,)).await } - 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 f_1(&self, arg0: List, arg1: serde_bytes::ByteBuf, arg2: Option) -> Result<()> { + pub async fn f_1(&self, arg0: &List, arg1: &serde_bytes::ByteBuf, arg2: &Option) -> Result<()> { ic_cdk::call(self.0, "f1", (arg0,arg1,arg2,)).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 } - pub async fn G11(&self, id: CanisterId, list: MyList, is_okay: Option, arg3: Nested) -> Result<(i128,Broker,NestedRes,)> { + pub async fn G11(&self, id: &CanisterId, list: &MyList, is_okay: &Option, arg3: &Nested) -> Result<(i128,Broker,NestedRes,)> { ic_cdk::call(self.0, "g1", (id,list,is_okay,arg3,)).await } - pub async fn h(&self, arg0: Vec>, arg1: HArg1, arg2: Option) -> Result<(HRet,)> { + pub async fn h(&self, arg0: &Vec>, arg1: &HArg1, arg2: &Option) -> Result<(HRet,)> { ic_cdk::call(self.0, "h", (arg0,arg1,arg2,)).await } - pub async fn i(&self, arg0: MyList, arg1: FArg1) -> Result<(Option,Res,)> { + pub async fn i(&self, arg0: &MyList, arg1: &FArg1) -> Result<(Option,Res,)> { ic_cdk::call(self.0, "i", (arg0,arg1,)).await } - pub async fn x(&self, arg0: A, arg1: B) -> Result<(Option,Option,std::result::Result,)> { + pub async fn x(&self, arg0: &A, arg1: &B) -> Result<(Option,Option,std::result::Result,)> { ic_cdk::call(self.0, "x", (arg0,arg1,)).await } } diff --git a/rust/candid_parser/tests/assets/ok/fieldnat.rs b/rust/candid_parser/tests/assets/ok/fieldnat.rs index 607c0445..93720cb9 100644 --- a/rust/candid_parser/tests/assets/ok/fieldnat.rs +++ b/rust/candid_parser/tests/assets/ok/fieldnat.rs @@ -29,25 +29,25 @@ pub struct FooRet { pub _2_: candid::Int, pub _2: candid::Int } pub struct Service(pub Principal); impl Service { - pub async fn bab(&self, arg0: candid::Int, arg1: candid::Nat) -> Result<()> { + 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: BarArg) -> Result<(BarRet,)> { + 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,),)> { + 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: BazArg) -> Result<(BazRet,)> { + 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<(NonTuple,)> { + 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<(BibRet,)> { + pub async fn bib(&self, arg0: &(candid::Int,)) -> Result<(BibRet,)> { ic_cdk::call(self.0, "bib", (arg0,)).await } - pub async fn foo(&self, arg0: FooArg) -> Result<(FooRet,)> { + pub async fn foo(&self, arg0: &FooArg) -> Result<(FooRet,)> { ic_cdk::call(self.0, "foo", (arg0,)).await } } diff --git a/rust/candid_parser/tests/assets/ok/keyword.rs b/rust/candid_parser/tests/assets/ok/keyword.rs index ae002bb1..20df13b4 100644 --- a/rust/candid_parser/tests/assets/ok/keyword.rs +++ b/rust/candid_parser/tests/assets/ok/keyword.rs @@ -45,34 +45,34 @@ 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,)> { + pub async fn field(&self, arg0: &FieldArg) -> Result<(FieldRet,)> { ic_cdk::call(self.0, "field", (arg0,)).await } - pub async fn fieldnat(&self, arg0: FieldnatArg) -> Result<((candid::Int,),)> { + 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<()> { + 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<(serde_bytes::ByteBuf,)> { + 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: Return) -> Result<()> { + pub async fn service(&self, arg0: &Return) -> Result<()> { ic_cdk::call(self.0, "service", (arg0,)).await } - pub async fn tuple(&self, arg0: (candid::Int,serde_bytes::ByteBuf,String,)) -> Result<((candid::Int,u8,),)> { + pub async fn tuple(&self, arg0: &(candid::Int,serde_bytes::ByteBuf,String,)) -> Result<((candid::Int,u8,),)> { ic_cdk::call(self.0, "tuple", (arg0,)).await } - pub async fn variant(&self, arg0: VariantArg) -> Result<()> { + pub async fn variant(&self, arg0: &VariantArg) -> Result<()> { ic_cdk::call(self.0, "variant", (arg0,)).await } } diff --git a/rust/candid_parser/tests/assets/ok/management.rs b/rust/candid_parser/tests/assets/ok/management.rs index a3715bbe..311f8e1d 100644 --- a/rust/candid_parser/tests/assets/ok/management.rs +++ b/rust/candid_parser/tests/assets/ok/management.rs @@ -205,67 +205,67 @@ pub struct UpdateSettingsArg { 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 { + pub async fn bitcoin_get_balance(&self, arg0: &GetBalanceRequest) -> Result { 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, arg0: GetCurrentFeePercentilesRequest) -> Result> { + pub async fn bitcoin_get_current_fee_percentiles(&self, arg0: &GetCurrentFeePercentilesRequest) -> Result> { 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, arg0: GetUtxosRequest) -> Result { + pub async fn bitcoin_get_utxos(&self, arg0: &GetUtxosRequest) -> Result { 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, arg0: SendTransactionRequest) -> Result<()> { + pub async fn bitcoin_send_transaction(&self, arg0: &SendTransactionRequest) -> Result<()> { 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, arg0: CanisterStatusArg) -> Result { + pub async fn canister_status(&self, arg0: &CanisterStatusArg) -> Result { 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, arg0: CreateCanisterArg) -> Result { + pub async fn create_canister(&self, arg0: &CreateCanisterArg) -> Result { 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, arg0: DeleteCanisterArg) -> Result<()> { + 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, arg0: DepositCyclesArg) -> Result<()> { + 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, arg0: EcdsaPublicKeyArg) -> Result { + pub async fn ecdsa_public_key(&self, arg0: &EcdsaPublicKeyArg) -> Result { 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, arg0: HttpRequestArg) -> Result { + pub async fn http_request(&self, arg0: &HttpRequestArg) -> Result { 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, arg0: InstallCodeArg) -> Result<()> { + 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, arg0: ProvisionalCreateCanisterWithCyclesArg) -> Result { + pub async fn provisional_create_canister_with_cycles(&self, arg0: &ProvisionalCreateCanisterWithCyclesArg) -> Result { 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, arg0: ProvisionalTopUpCanisterArg) -> Result<()> { + pub async fn provisional_top_up_canister(&self, arg0: &ProvisionalTopUpCanisterArg) -> Result<()> { 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)?) @@ -275,27 +275,27 @@ impl<'a> Service<'a> { 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, arg0: SignWithEcdsaArg) -> Result { + pub async fn sign_with_ecdsa(&self, arg0: &SignWithEcdsaArg) -> Result { 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, arg0: StartCanisterArg) -> Result<()> { + 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, arg0: StopCanisterArg) -> Result<()> { + 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, arg0: UninstallCodeArg) -> Result<()> { + 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, arg0: UpdateSettingsArg) -> Result<()> { + 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)?) diff --git a/rust/candid_parser/tests/assets/ok/recursion.rs b/rust/candid_parser/tests/assets/ok/recursion.rs index 480962c7..236f2254 100644 --- a/rust/candid_parser/tests/assets/ok/recursion.rs +++ b/rust/candid_parser/tests/assets/ok/recursion.rs @@ -31,10 +31,10 @@ candid::define_service!(pub S : { 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_parser/tests/assets/ok/unicode.rs b/rust/candid_parser/tests/assets/ok/unicode.rs index ec2ebbe1..87c596f4 100644 --- a/rust/candid_parser/tests/assets/ok/unicode.rs +++ b/rust/candid_parser/tests/assets/ok/unicode.rs @@ -29,16 +29,16 @@ pub enum B { pub struct Service(pub Principal); impl Service { - pub async fn _0_(&self, arg0: candid::Nat) -> Result<(candid::Nat,)> { + pub async fn _0_(&self, arg0: &candid::Nat) -> Result<(candid::Nat,)> { ic_cdk::call(self.0, "", (arg0,)).await } pub async fn _356566390_(&self) -> Result<()> { ic_cdk::call(self.0, "✈️ 🚗 ⛱️ ", ()).await } - pub async fn _3300066460_(&self, arg0: A) -> Result<(B,)> { + pub async fn _3300066460_(&self, arg0: &A) -> Result<(B,)> { ic_cdk::call(self.0, "函数名", (arg0,)).await } - pub async fn _2669435454_(&self, arg0: candid::Nat) -> Result<(candid::Nat,)> { + pub async fn _2669435454_(&self, arg0: &candid::Nat) -> Result<(candid::Nat,)> { ic_cdk::call(self.0, "👀", (arg0,)).await } } diff --git a/tools/didc/Cargo.toml b/tools/didc/Cargo.toml index d6a61b46..19ab3a7f 100644 --- a/tools/didc/Cargo.toml +++ b/tools/didc/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] candid_parser = { path = "../../rust/candid_parser", features = ["all"] } clap = { version = "4.5", features = ["derive"] } -pretty-hex = "0.2.1" +pretty-hex = "0.4.1" hex.workspace = true anyhow.workspace = true rand.workspace = true diff --git a/tools/didc/src/main.rs b/tools/didc/src/main.rs index bed24ab0..68861b2a 100644 --- a/tools/didc/src/main.rs +++ b/tools/didc/src/main.rs @@ -225,7 +225,9 @@ fn main() -> Result<()> { let configs = load_config(&config)?; let (env, mut actor) = pretty_check_file(&input)?; if !methods.is_empty() { - actor = candid_parser::bindings::analysis::project_methods(&env, &actor, &methods); + actor = Some(candid_parser::bindings::analysis::project_methods( + &env, &actor, methods, + )?); } let content = match target.as_str() { "js" => candid_parser::bindings::javascript::compile(&env, &actor), From 34b4eb0b581bbf04902e20bf1370e3a293d1956f Mon Sep 17 00:00:00 2001 From: Yan Chen <48968912+chenyan-dfinity@users.noreply.github.com> Date: Mon, 29 Jul 2024 18:08:11 -0700 Subject: [PATCH 5/6] remove macos 11 test (#565) --- .github/workflows/release.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9bba0839..cb88cab5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -82,8 +82,6 @@ jobs: asset_name: didc-macos - os: macos-12 asset_name: didc-macos - - os: macos-11 - asset_name: didc-macos steps: - name: Get executable id: download From bba0b53d47ba3a14bc7da0b2b11119f8afcea37e Mon Sep 17 00:00:00 2001 From: David Frank Date: Fri, 9 Aug 2024 18:03:06 +0200 Subject: [PATCH 6/6] Remove unnecessary allocation/copy from the string serialization implementation (#566) --- rust/candid/src/ser.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/candid/src/ser.rs b/rust/candid/src/ser.rs index 15750555..79064070 100644 --- a/rust/candid/src/ser.rs +++ b/rust/candid/src/ser.rs @@ -147,9 +147,9 @@ impl<'a> types::Serializer for &'a mut ValueSerializer { serialize_num!(float64, f64, write_f64::); fn serialize_text(self, v: &str) -> Result<()> { - let mut buf = Vec::from(v.as_bytes()); + let buf = v.as_bytes(); self.write_leb128(buf.len() as u64)?; - self.value.append(&mut buf); + self.value.extend_from_slice(buf); Ok(()) } fn serialize_null(self, _v: ()) -> Result<()> { @@ -316,9 +316,9 @@ impl TypeSerialize { sleb128_encode(&mut buf, Opcode::Service as i64)?; leb128_encode(&mut buf, ms.len() as u64)?; for (id, ty) in ms { - let mut name = Vec::from(id.as_bytes()); + let name = id.as_bytes(); leb128_encode(&mut buf, name.len() as u64)?; - buf.append(&mut name); + buf.extend_from_slice(name); self.encode(&mut buf, ty)?; } }