Skip to content

Commit

Permalink
more improvements to Configs (#548)
Browse files Browse the repository at this point in the history
* add clone for configs

* add open_path

* report unused

* add stub

* add rust parser to extract cdk functions; didc to take external.rust section

* fix mode

* refactor to report span

* checkpoint, use codespan_reporting

* good

* fix

* move rust_check to cdk

* bump version
  • Loading branch information
chenyan-dfinity authored May 14, 2024
1 parent b0622bb commit a21d1b8
Show file tree
Hide file tree
Showing 21 changed files with 289 additions and 133 deletions.
146 changes: 70 additions & 76 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions rust/candid_parser/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "candid_parser"
version = "0.2.0-beta.0"
version = "0.2.0-beta.1"
edition = "2021"
rust-version.workspace = true
authors = ["DFINITY Team"]
Expand Down Expand Up @@ -29,7 +29,7 @@ anyhow.workspace = true
serde.workspace = true

lalrpop-util = "0.20.0"
logos = "0.13"
logos = "0.14"
convert_case = "0.6"
handlebars = "5.1"
toml = { version = "0.8", default-features = false, features = ["parse"] }
Expand Down
83 changes: 66 additions & 17 deletions rust/candid_parser/src/bindings/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ impl<'a> State<'a> {
res
}
fn pp_function(&mut self, id: &str, func: &Function) -> Method {
use candid::types::internal::FuncMode;
let old = self.state.push_state(&StateElem::Label(id));
let name = self
.state
Expand Down Expand Up @@ -424,7 +425,13 @@ impl<'a> State<'a> {
res
})
.collect();
let mode = if func.is_query() { "query" } else { "update" }.to_string();
let mode = match func.modes.first() {
None => "update",
Some(FuncMode::Query) => "query",
Some(FuncMode::CompositeQuery) => "composite_query",
Some(FuncMode::Oneway) => "update",
}
.to_string();
let res = Method {
name,
original_name: id.to_string(),
Expand Down Expand Up @@ -478,19 +485,19 @@ impl<'a> State<'a> {
}
#[derive(Serialize, Debug)]
pub struct Output {
type_defs: String,
methods: Vec<Method>,
init_args: Option<Vec<(String, String)>>,
pub type_defs: String,
pub methods: Vec<Method>,
pub init_args: Option<Vec<(String, String)>>,
}
#[derive(Serialize, Debug)]
pub struct Method {
name: String,
original_name: String,
args: Vec<(String, String)>,
rets: Vec<String>,
mode: String,
pub name: String,
pub original_name: String,
pub args: Vec<(String, String)>,
pub rets: Vec<String>,
pub mode: String,
}
pub fn emit_bindgen(tree: &Config, env: &TypeEnv, actor: &Option<Type>) -> Output {
pub fn emit_bindgen(tree: &Config, env: &TypeEnv, actor: &Option<Type>) -> (Output, Vec<String>) {
let (env, actor) = nominalize_all(env, actor);
let def_list: Vec<_> = if let Some(actor) = &actor {
chase_actor(&env, actor).unwrap()
Expand All @@ -508,11 +515,15 @@ pub fn emit_bindgen(tree: &Config, env: &TypeEnv, actor: &Option<Type>) -> Outpu
} else {
(Vec::new(), None)
};
Output {
type_defs: defs.pretty(LINE_WIDTH).to_string(),
methods,
init_args,
}
let unused = state.state.report_unused();
(
Output {
type_defs: defs.pretty(LINE_WIDTH).to_string(),
methods,
init_args,
},
unused,
)
}
pub fn output_handlebar(output: Output, config: ExternalConfig, template: &str) -> String {
let hbs = get_hbs();
Expand All @@ -522,11 +533,13 @@ pub fn output_handlebar(output: Output, config: ExternalConfig, template: &str)
external: BTreeMap<String, String>,
type_defs: String,
methods: Vec<Method>,
init_args: Option<Vec<(String, String)>>,
}
let data = HBOutput {
type_defs: output.type_defs,
methods: output.methods,
external: config.0,
init_args: output.init_args,
};
hbs.render_template(template, &data).unwrap()
}
Expand All @@ -536,6 +549,7 @@ impl Config {
Self(ConfigTree::from_configs("rust", configs).unwrap())
}
}
#[derive(Deserialize)]
pub struct ExternalConfig(pub BTreeMap<String, String>);
impl Default for ExternalConfig {
fn default() -> Self {
Expand All @@ -560,9 +574,13 @@ pub fn compile(
let source = match external.0.get("target").map(|s| s.as_str()) {
Some("canister_call") | None => include_str!("rust_call.hbs"),
Some("agent") => include_str!("rust_agent.hbs"),
Some("stub") => include_str!("rust_stub.hbs"),
_ => unimplemented!(),
};
let output = emit_bindgen(tree, env, actor);
let (output, unused) = emit_bindgen(tree, env, actor);
for e in unused {
eprintln!("WARNING: path {e} is unused");
}
output_handlebar(output, external, source)
}

Expand Down Expand Up @@ -754,7 +772,6 @@ fn nominalize_all(env: &TypeEnv, actor: &Option<Type>) -> (TypeEnv, Option<Type>
.map(|ty| nominalize(&mut res, &mut vec![], ty));
(res, actor)
}

fn get_hbs() -> handlebars::Handlebars<'static> {
use handlebars::*;
let mut hbs = Handlebars::new();
Expand Down Expand Up @@ -853,5 +870,37 @@ fn get_hbs() -> handlebars::Handlebars<'static> {
},
),
);
hbs.register_helper(
"cdk_attribute",
Box::new(
|h: &Helper,
_: &Handlebars,
_: &Context,
_: &mut RenderContext,
out: &mut dyn Output|
-> HelperResult {
let mode = h.param(0).unwrap().value().as_str().unwrap();
let name = h.param(1).unwrap().value().as_str().unwrap();
let original_name = h.param(2).unwrap().value().as_str().unwrap();
if mode == "update" {
out.write("update")?;
} else {
out.write("query")?;
}
let mut attrs = Vec::new();
if mode == "composite_query" {
attrs.push("composite = true".to_string());
}
if name != original_name {
attrs.push(format!("name = \"{}\"", original_name.escape_debug()));
}
let attrs = attrs.join(", ");
if !attrs.is_empty() {
out.write(&format!("({attrs})"))?;
}
Ok(())
},
),
);
hbs
}
2 changes: 1 addition & 1 deletion rust/candid_parser/src/bindings/rust_agent.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ 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}}> {
let args = Encode!({{#each this.args}}&{{this.0}}{{#unless @last}},{{/unless}}{{/each}})?;
let bytes = self.1.{{this.mode}}(&self.0, "{{escape_debug this.original_name}}").with_arg(args).{{#if (eq this.mode "query")}}call{{else}}call_and_wait(){{/if}}.await?;
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}})?)
}
{{/each}}
Expand Down
2 changes: 1 addition & 1 deletion rust/candid_parser/src/bindings/rust_call.hbs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// This is an experimental feature to generate Rust binding from Candid.
// You may want to manually adjust some of the types.
#![allow(dead_code, unused_imports)]
use {{candid_crate}}::{self, CandidType, Deserialize, Principal, Encode, Decode};
use {{candid_crate}}::{self, CandidType, Deserialize, Principal};
use ic_cdk::api::call::CallResult as Result;

{{type_defs}}
Expand Down
18 changes: 18 additions & 0 deletions rust/candid_parser/src/bindings/rust_stub.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// This is an experimental feature to generate Rust binding from Candid.
// You may want to manually adjust some of the types.
#![allow(dead_code, unused_imports)]
use {{candid_crate}}::{self, CandidType, Deserialize, Principal};

{{type_defs}}
{{#if init_args}}
#[ic_cdk::init]
fn init({{#each init_args}}{{#if (not @first)}}, {{/if}}{{this.0}}: {{this.1}}{{/each}}) {
unimplemented!()
}
{{/if}}
{{#each methods}}
#[ic_cdk::{{cdk_attribute this.mode this.name this.original_name}}]
fn {{this.name}}({{#each this.args}}{{#if (not @first)}}, {{/if}}{{this.0}}: {{this.1}}{{/each}}) -> {{vec_to_arity this.rets}} {
unimplemented!()
}
{{/each}}
Loading

0 comments on commit a21d1b8

Please sign in to comment.