candid/
lib.rs

1//! # Candid
2//!
3//! Candid is an interface description language (IDL) for interacting with _canisters_ (also known as _services_ or _actors_) running on the Internet Computer.
4//!
5//! There are three common ways that you might find yourself needing to work with Candid in Rust.
6//! - As a typed Rust data structure. When you write canisters or frontend in Rust, you want to have a seamless way of converting data between Rust and Candid.
7//! - As an untyped Candid value. When you write generic tools for the Internet Computer without knowing the type of the Candid data.
8//! - As text data. When you get the data from CLI or read from a file, you can use the provided parser to send/receive messages.
9//!
10//! Candid provides efficient, flexible and safe ways of converting data between each of these representations.
11//!
12//! ## Operating on native Rust values
13//!
14//! We are using a builder pattern to encode/decode Candid messages, see [`candid::ser::IDLBuilder`](ser/struct.IDLBuilder.html) for serialization and [`candid::de::IDLDeserialize`](de/struct.IDLDeserialize.html) for deserialization.
15//!
16//! ```
17//! // Serialize 10 numbers to Candid binary format
18//! let mut ser = candid::ser::IDLBuilder::new();
19//! for i in 0..10 {
20//!   ser.arg(&i)?;
21//! }
22//! let bytes: Vec<u8> = ser.serialize_to_vec()?;
23//!
24//! // Deserialize Candid message and verify the values match
25//! let mut de = candid::de::IDLDeserialize::new(&bytes)?;
26//! let mut i = 0;
27//! while !de.is_done() {
28//!   let x = de.get_value::<i32>()?;
29//!   assert_eq!(x, i);
30//!   i += 1;
31//! }
32//! de.done()?;
33//! # Ok::<(), candid::Error>(())
34//! ```
35//!
36//! Candid provides functions for encoding/decoding a Candid message in a type-safe way.
37//!
38//! ```
39//! use candid::{encode_args, decode_args};
40//! // Serialize two values [(42, "text")] and (42u32, "text")
41//! let bytes: Vec<u8> = encode_args((&[(42, "text")], &(42u32, "text")))?;
42//! // Deserialize the first value as type Vec<(i32, &str)>,
43//! // and the second value as type (u32, String)
44//! let (a, b): (Vec<(i32, &str)>, (u32, String)) = decode_args(&bytes)?;
45//!
46//! assert_eq!(a, [(42, "text")]);
47//! assert_eq!(b, (42u32, "text".to_string()));
48//! # Ok::<(), candid::Error>(())
49//! ```
50//!
51//! We also provide macros for encoding/decoding Candid message in a convenient way.
52//!
53//! ```
54//! use candid::{Encode, Decode};
55//! // Serialize two values [(42, "text")] and (42u32, "text")
56//! let bytes: Vec<u8> = Encode!(&[(42, "text")], &(42u32, "text"))?;
57//! // Deserialize the first value as type Vec<(i32, &str)>,
58//! // and the second value as type (u32, String)
59//! let (a, b) = Decode!(&bytes, Vec<(i32, &str)>, (u32, String))?;
60//!
61//! assert_eq!(a, [(42, "text")]);
62//! assert_eq!(b, (42u32, "text".to_string()));
63//! # Ok::<(), candid::Error>(())
64//! ```
65//!
66//! The [`Encode!`](macro.Encode.html) macro takes a sequence of Rust values, and returns a binary format `Vec<u8>` that can be sent over the wire.
67//! The [`Decode!`](macro.Decode.html) macro takes the binary message and a sequence of Rust types that you want to decode into, and returns a tuple
68//! of Rust values of the given types.
69//!
70//! Note that a fixed Candid message may be decoded in multiple Rust types. For example,
71//! we can decode a Candid `text` type into either `String` or `&str` in Rust.
72//!
73//! ## Operating on user defined struct/enum
74//!
75//! We use trait [`CandidType`](types/trait.CandidType.html) for serialization. Deserialization requires both [`CandidType`](types/trait.CandidType.html) and Serde's [`Deserialize`](trait.Deserialize.html) trait.
76//! Any type that implements these two traits can be used for serialization and deserialization.
77//! This includes built-in Rust standard library types like `Vec<T>` and `Result<T, E>`, as well as any structs
78//! or enums annotated with `#[derive(CandidType, Deserialize)]`.
79//!
80//! We do not use Serde's `Serialize` trait because Candid requires serializing types along with the values.
81//! This is difficult to achieve in `Serialize`, especially for enum types. Besides serialization, [`CandidType`](types/trait.CandidType.html)
82//! trait also converts Rust type to Candid type defined as [`candid::types::Type`](types/internal/enum.Type.html).
83//!
84//! ```
85//! #[cfg(feature = "serde_bytes")]
86//! # fn f() -> Result<(), candid::Error> {
87//! use candid::{Encode, Decode, CandidType, Deserialize};
88//! #[derive(CandidType, Deserialize)]
89//! # #[derive(Debug, PartialEq)]
90//! enum List {
91//!     #[serde(rename = "nil")]
92//!     Nil,
93//!     #[serde(with = "serde_bytes")]
94//!     Node(Vec<u8>),
95//!     Cons(i32, Box<List>),
96//! }
97//! let list = List::Cons(42, Box::new(List::Nil));
98//!
99//! let bytes = Encode!(&list)?;
100//! let res = Decode!(&bytes, List)?;
101//! assert_eq!(res, list);
102//! # Ok(())
103//! # }
104//! ```
105//!
106//! Note that if you are deriving `Deserialize` trait from Candid, you need to import `serde` as a dependency in
107//! your project, as the derived implementation will refer to the `serde` crate.
108//!
109//! ## Supported `serde` Attributes
110//!
111//! Due to fundamental differences between Candid's type system and the general `serde` data model,
112//! we cannot support all `serde` attributes. The following attributes are officially supported
113//! when working with `CandidType` and guaranteed to function correctly:
114//!
115//! ### 1. `rename`
116//!
117//! We support serde's rename attributes for each field, namely `#[serde(rename = "foo")]`
118//! and `#[serde(rename(serialize = "foo", deserialize = "foo"))]`.
119//! This is useful when interoperating between Rust and Motoko canisters involving variant types, because
120//! they use different naming conventions for field names.
121//!
122//! Please note that `rename_all` and `rename_all_fields` are not supported.
123//!
124//! ### 2. `serde_bytes`
125//!
126//! We support `#[serde(with = "serde_bytes")]` for efficient handling of `&[u8]` and `Vec<u8>`. You can
127//! also use the wrapper type `serde_bytes::ByteBuf` and `serde_bytes::Bytes`.
128//!
129//! ## Operating on big integers
130//!
131//! To support big integer types [`Candid::Int`](types/number/struct.Int.html) and [`Candid::Nat`](types/number/struct.Nat.html),
132//! we use the `num_bigint` crate. We provide interface to convert `i64`, `u64`, `&str` and `&[u8]` to big integers.
133//! You can also use `i128` and `u128` to represent Candid `int` and `nat` types respectively (decoding will fail if
134//! the number is more than 128 bits).
135//! ```
136//! #[cfg(feature = "bignum")]
137//! # fn f() -> Result<(), candid::Error> {
138//! use candid::{Int, Nat, Encode, Decode};
139//! let x = "-10000000000000000000".parse::<Int>()?;
140//! let bytes = Encode!(&Nat::from(1024u32), &x)?;
141//! let (a, b) = Decode!(&bytes, Nat, Int)?;
142//! let (c, d) = Decode!(&bytes, u128, i128)?;
143//! assert_eq!(a + 1u8, 1025u32);
144//! assert_eq!(b, Int::parse(b"-10000000000000000000")?);
145//! # Ok(())
146//! # }
147//! ```
148//!
149//! ## Operating on reference types
150//!
151//! The type of function and service references cannot be derived automatically. We provide
152//! two macros [`define_function!`](macro.define_function.html) and [`define_service!`](macro.define_service.html) to help defining the reference types. To specify reference types in the macro, you need to use the corresponding Rust types,
153//! instead of the Candid types.
154//!
155//! ```
156//! #[cfg(feature = "bignum")]
157//! # fn f() -> Result<(), candid::Error> {
158//! use candid::{define_function, define_service, func, Encode, Decode, Principal};
159//! let principal = Principal::from_text("aaaaa-aa").unwrap();
160//!
161//! define_function!(pub CustomFunc : (u8, &str) -> (u128));
162//! let func = CustomFunc::new(principal, "method_name".to_string());
163//! assert_eq!(func, Decode!(&Encode!(&func)?, CustomFunc)?);
164//!
165//! define_service!(MyService : {
166//!   "f": CustomFunc::ty();
167//!   "g": func!((candid::Int) -> (candid::Nat, CustomFunc) query)
168//! });
169//! let serv = MyService::new(principal);
170//! assert_eq!(serv, Decode!(&Encode!(&serv)?, MyService)?);
171//! # Ok(())
172//! # }
173//! ```
174//!
175//! ## Operating on untyped Candid values
176//!
177//! Any valid Candid value can be manipulated in an recursive enum representation [`candid::parser::value::IDLValue`](parser/value/enum.IDLValue.html).
178//! We use `ser.value_arg(v)` and `de.get_value::<IDLValue>()` for encoding and decoding the value.
179//! The use of Rust value and `IDLValue` can be intermixed.
180//!
181//! ```
182//! #[cfg(feature = "value")]
183//! # fn f() -> Result<(), candid::Error> {
184//! use candid::types::value::IDLValue;
185//! // Serialize Rust value Some(42u8) and IDLValue "hello"
186//! let bytes = candid::ser::IDLBuilder::new()
187//!     .arg(&Some(42u8))?
188//!     .value_arg(&IDLValue::Text("hello".to_string()))?
189//!     .serialize_to_vec()?;
190//!
191//! // Deserialize the first Rust value into IDLValue,
192//! // and the second IDLValue into Rust value
193//! let mut de = candid::de::IDLDeserialize::new(&bytes)?;
194//! let x = de.get_value::<IDLValue>()?;
195//! let y = de.get_value::<&str>()?;
196//! de.done()?;
197//!
198//! assert_eq!(x, IDLValue::Opt(Box::new(IDLValue::Nat8(42))));
199//! assert_eq!(y, "hello");
200//! # Ok(())
201//! # }
202//! ```
203//!
204//! ## Building the library as a JS/Wasm package
205//!
206//! With the help of `wasm-bindgen` and `wasm-pack`, we can build the library as a Wasm binary and run in the browser.
207//! This is useful for client-side UIs and parsing did files in JavaScript.
208//!
209//! Create a new project with the following `Cargo.toml`.
210//!
211//! ```toml
212//! [lib]
213//! crate-type = ["cdylib"]
214//!
215//! [dependencies]
216//! wasm-bindgen = "0.2"
217//! candid = "0.9.0"
218//! candid_parser = "0.1.0"
219//!
220//! [profile.release]
221//! lto = true
222//! opt-level = 'z'
223//! ```
224//!
225//! Expose the methods in `lib.rs`
226//!
227//! ```ignore
228//! use candid::TypeEnv;
229//! use candid_parser::{check_prog, IDLProg};
230//! use wasm_bindgen::prelude::*;
231//! #[wasm_bindgen]
232//! pub fn did_to_js(prog: String) -> Option<String> {
233//!   let ast = prog.parse::<IDLProg>().ok()?;
234//!   let mut env = TypeEnv::new();
235//!   let actor = check_prog(&mut env, &ast).ok()?;
236//!   Some(candid_parser::bindings::javascript::compile(&env, &actor))
237//! }
238//! ```
239//!
240//! ### Building
241//!
242//! ```shell
243//! cargo install wasm-pack
244//! wasm-pack build --target bundler
245//! wasm-opt --strip-debug -Oz pkg/didc_bg.wasm -o pkg/didc_bg.wasm
246//! ```
247//!
248//! ### Usage
249//!
250//! ```js
251//! const didc = import("pkg/didc");
252//! didc.then((mod) => {
253//!   const service = "service : {}";
254//!   const js = mod.did_to_js(service);
255//! });
256//! ```
257
258// only enables the `doc_cfg` feature when
259// the `docsrs` configuration attribute is defined
260#![cfg_attr(docsrs, feature(doc_cfg))]
261
262pub use candid_derive::{candid_method, export_service, CandidType};
263pub use serde::Deserialize;
264
265pub mod error;
266pub use error::{Error, Result};
267
268pub mod types;
269#[cfg(feature = "bignum")]
270pub use types::number::{Int, Nat};
271pub use types::CandidType;
272pub use types::{
273    arc,
274    principal::Principal,
275    rc,
276    reference::{Func, Service},
277    reserved::{Empty, Reserved},
278    result::MotokoResult,
279    TypeEnv,
280};
281
282#[allow(dead_code)]
283pub mod binary_parser;
284pub mod de;
285pub use de::DecoderConfig;
286pub mod ser;
287
288pub mod utils;
289pub use utils::{
290    decode_args, decode_args_with_config, decode_args_with_decoding_and_skipping_quota,
291    decode_args_with_decoding_quota, decode_args_with_skipping_quota, decode_one,
292    decode_one_with_config, decode_one_with_decoding_and_skipping_quota,
293    decode_one_with_decoding_quota, decode_one_with_skipping_quota, encode_args, encode_one,
294    write_args,
295};
296
297#[cfg_attr(docsrs, doc(cfg(feature = "value")))]
298#[cfg(feature = "value")]
299pub use types::value::{IDLArgs, IDLValue};
300#[cfg_attr(docsrs, doc(cfg(feature = "printer")))]
301#[cfg(feature = "printer")]
302pub mod pretty;
303
304// Candid hash function comes from
305// https://caml.inria.fr/pub/papers/garrigue-polymorphic_variants-ml98.pdf
306// Not public API. Only used by tests.
307// Remember to update the same function in candid_derive if you change this function.
308#[doc(hidden)]
309#[inline]
310pub fn idl_hash(id: &str) -> u32 {
311    let mut s: u32 = 0;
312    for c in id.as_bytes() {
313        s = s.wrapping_mul(223).wrapping_add(*c as u32);
314    }
315    s
316}