Automatically generate candid from rust sources

I see the macros candid::export_service!(), but how do I use it?
Should I implement another macros that will call __export_service() and write a file with the content it returns or what?

2 Likes

Try this

}

export_service!();

#[ic_cdk_macros::query(name = "__get_candid_interface_tmp_hack")]
fn export_candid() -> String {
    __export_service()
}

(taken from candid/lib.rs at a555d77704d691bb8f34e21a049d44ba0acee3f8 · dfinity/candid · GitHub).

It would probably a reasonable feature request for cdk-rs to provide all of the above under a single macro (expose_candid_interface()). This would especially be useful if the underlying interface changes – then people just have to recompile their canisters, but not change any code.

6 Likes

Thanks!

But what do I write under candid key in my dfx.json?
In the mentioned example there is a valid candid file already written by hand.

The problem I want to solve is to generate .did file automatically.

1 Like

There is a PR for generating did files: feat: export candid by chenyan-dfinity · Pull Request #28 · dfinity/cdk-rs · GitHub

The proposed solution requires compiling the code twice, one for WASI and one for IC. Not ideal, but works.

2 Likes

I believe it pays off to have your .did file committed to the repository, documented, and curated manually. This is the face of your canister, the main thing that people who integrate with your canister will care about. It’s a lot like a header file for a C/C++ library or a module interface file in OCaml.

Being able to generate a .did file automatically is still very useful:

  1. You can use it get the first version of the .did file that you can edit by hand afterwards.
  2. You can use it to generate the actual interface of your canister and pipe it to didc subtype as a precommit hook to make sure that the manually curated .did file is not obsolete.

IC governance canister adds a main function that outputs the .did file when compiled in native mode:

The generated governance.did file is also committed to the repository: ic/governance.did at 40ab84f4fcb9e6c2441e91a59cfaa5acf84fe38d · dfinity/ic · GitHub

8 Likes

I would love to see this! Is the team interested in adding this? I’m happy to do the PR if it will be accepted

Why is this macro necessary #[candid_method(query)] to generate the candid types? If I expose a canister method as through #[query] or #[update], then shouldn’t it be part of the Candid interface?

Even if it is desirable to allow not exposing an already-exposed method in the Candid interface, would it not be better to opt out instead of having to opt in?

I’ve already gone through the work of annotating my functions with #[query] or #[update], thus they are exposed, thus I want them in the Candid.

4 Likes

Also, has anyone written a tool that will convert a .did file into Rust types? That would be super useful for interoperability between canisters written in different languages. I once spent most of my integration time with a canister just writing Rust types because all I had was the .did files. The logic was relatively simple but so much of my time was spent basically transpiling Candid into Rust.

https://github.com/dfinity/candid/blob/master/rust/candid/src/codegen/rust.rs
I don’t know if such a tool exists, but #[import] macro does exactly that in a background.

1 Like

didc bind a.did -t rs

9 Likes

I am forever changed

3 Likes

I am getting this error

> didc bind can.did -t rs 
error: 'rs' isn't a valid value for '--target <target>'
        [possible values: did, js, mo, ts]

Is that a newer version?
I have v 0.1.0

2 Likes

Yes, please download the latest release, which is v0.1.3: Releases · dfinity/candid · GitHub

3 Likes

Generating service descriptions says:

After you develop a service in a language like Rust, however, there’s currently no way to automatically generate the service description in Candid. Therefore, if you write a program for a service in Rust or C, you need to write the Candid interface description manually

The doc is correct in the sense that we don’t have a user-friendly solution to automatically generate Rust bindings yet. didc can generate a Rust binding, but in many cases, you still need to hand-tune the output, for example, to derive more traits, add lifetime, add Box/Arc. Will update the doc once we have a configurable way to guide the binding generation.

There may be confusion: Paul linked to “generating service description”, i.e. going from rust to Candid. Yan seems to talk about going from Candid to Rust.

For Rust-to-Candid, we do have some macros, don’t we? The Candid guide should be updated to reflect that.

3 Likes

Ah, right. Rust-to-Candid is fine. We plan to include that macros into the CDK, so that users don’t need to write them anymore.

any tentative timeline for this? including docs

2 Likes

Any update on automatically generating the Candid from Rust? It would be so nice for Rust/custom canisters to have the same experience as Motoko where all of the Candid generation is hidden away unless the developer explicitly wants to write a Candid file by hand.

This would help the Azle and Kybra CDKs a lot.

1 Like

We prioritized this work in 2023 Q2. If everything goes well, we will get it in April.

5 Likes