use crate::{
dto::error::Error,
workflow::ic::call::{
CallBuilder as WorkflowCallBuilder, CallResult as WorkflowCallResult, CallWorkflow,
},
};
use candid::{
CandidType, Principal,
utils::{ArgumentDecoder, ArgumentEncoder},
};
use serde::de::DeserializeOwned;
use std::borrow::Cow;
pub struct Call;
impl Call {
#[must_use]
pub fn bounded_wait(canister_id: impl Into<Principal>, method: &str) -> CallBuilder<'static> {
CallBuilder {
inner: CallWorkflow::bounded_wait(canister_id, method),
}
}
#[must_use]
pub fn unbounded_wait(canister_id: impl Into<Principal>, method: &str) -> CallBuilder<'static> {
CallBuilder {
inner: CallWorkflow::unbounded_wait(canister_id, method),
}
}
}
pub struct CallBuilder<'a> {
inner: WorkflowCallBuilder<'a>,
}
impl CallBuilder<'_> {
pub fn with_arg<A>(self, arg: A) -> Result<Self, Error>
where
A: CandidType,
{
Ok(Self {
inner: self.inner.with_arg(arg).map_err(Error::from)?,
})
}
pub fn with_args<A>(self, args: A) -> Result<Self, Error>
where
A: ArgumentEncoder,
{
Ok(Self {
inner: self.inner.with_args(args).map_err(Error::from)?,
})
}
#[must_use]
pub fn with_raw_args<'b>(self, args: impl Into<Cow<'b, [u8]>>) -> CallBuilder<'b> {
CallBuilder {
inner: self.inner.with_raw_args(args),
}
}
#[must_use]
pub fn with_cycles(self, cycles: u128) -> Self {
Self {
inner: self.inner.with_cycles(cycles),
}
}
pub async fn execute(self) -> Result<CallResult, Error> {
Ok(CallResult {
inner: self.inner.execute().await.map_err(Error::from)?,
})
}
pub async fn execute_candid<R>(self) -> Result<R, Error>
where
R: CandidType + DeserializeOwned,
{
self.execute().await?.candid()
}
pub async fn execute_candid_tuple<R>(self) -> Result<R, Error>
where
R: for<'de> ArgumentDecoder<'de>,
{
self.execute().await?.candid_tuple()
}
}
pub struct CallResult {
inner: WorkflowCallResult,
}
impl CallResult {
pub fn candid<R>(&self) -> Result<R, Error>
where
R: CandidType + DeserializeOwned,
{
self.inner.candid().map_err(Error::from)
}
pub fn candid_tuple<R>(&self) -> Result<R, Error>
where
R: for<'de> ArgumentDecoder<'de>,
{
self.inner.candid_tuple().map_err(Error::from)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ops::runtime::metrics::inter_canister_call::{
InterCanisterCallMetricKey, InterCanisterCallMetrics,
};
use std::collections::HashMap;
#[test]
fn public_builder_routes_through_instrumented_call_authority() {
InterCanisterCallMetrics::reset();
let target = Principal::from_slice(&[7; 29]);
let _builder = Call::bounded_wait(target, "example")
.with_arg(42_u64)
.expect("encode one argument")
.with_cycles(1_000);
let counts: HashMap<_, _> = InterCanisterCallMetrics::snapshot()
.entries
.into_iter()
.collect();
assert_eq!(
counts.get(&InterCanisterCallMetricKey {
target,
method: "example".to_string(),
}),
Some(&1)
);
}
}