candid/types/
reference.rs

1//! Data structure for Candid value Func and Service
2//! Note that `Func` and `Service` should not be used directly. We need to define a newtype for `Func` or `Service`,
3//! and manually `impl CandidType` for the newtype, in order to specify the correct reference type.
4//! We have two macros `define_function!` and `define_service!` to help defining the newtype.
5
6use super::principal::Principal;
7use super::{CandidType, Serializer, Type};
8use serde::de::{self, Deserialize, Visitor};
9use std::convert::TryFrom;
10use std::{fmt, io::Read};
11
12#[derive(PartialEq, Eq, Debug, Clone)]
13pub struct Func {
14    pub principal: Principal,
15    pub method: String,
16}
17#[derive(PartialEq, Eq, Debug, Clone)]
18pub struct Service {
19    pub principal: Principal,
20}
21
22#[macro_export]
23/// Define a function reference type.
24///
25/// `define_function!(pub MyFunc : (u8, &str) -> (Nat) query)` expands to `pub struct MyFunc(Func)`, which implements `CandidType` with the provided type. We also provide a constructor function `MyFunc::new(principal, method)`.
26macro_rules! define_function {
27    ( $vis:vis $func:ident : $($ty:tt)+ ) => {
28        #[derive($crate::Deserialize, PartialEq, Eq, Debug, Clone)]
29        $vis struct $func(pub $crate::types::reference::Func);
30        impl $crate::CandidType for $func {
31            fn _ty() -> $crate::types::Type {
32                $crate::func!($($ty)+)
33            }
34            fn idl_serialize<S: $crate::types::Serializer>(&self, serializer: S) -> std::result::Result<(), S::Error>
35            {
36                self.0.idl_serialize(serializer)
37            }
38        }
39        impl From<$crate::types::reference::Func> for $func {
40            fn from(v: $crate::types::reference::Func) -> Self {
41                Self(v)
42            }
43        }
44        impl $func {
45            pub fn new(principal: $crate::Principal, method: String) -> Self {
46                $func($crate::types::reference::Func { principal, method })
47            }
48        }
49    }
50}
51#[macro_export]
52/// Define a service reference type.
53///
54/// `define_service!(MyService : { "f": func!(() -> () query) })` expands to `struct MyService(Service)`, which implements `CandidType` with the provided type and `MyService::new(principal)`.
55macro_rules! define_service {
56    ( $vis:vis $serv:ident : { $($ty:tt)* } ) => {
57        #[derive($crate::Deserialize, PartialEq, Eq, Debug, Clone)]
58        $vis struct $serv(pub $crate::types::reference::Service);
59        impl $crate::CandidType for $serv {
60            fn _ty() -> $crate::types::Type {
61                $crate::service!{$($ty)*}
62            }
63            fn idl_serialize<S: $crate::types::Serializer>(&self, serializer: S) -> std::result::Result<(), S::Error>
64            {
65                self.0.idl_serialize(serializer)
66            }
67        }
68        impl From<$crate::types::reference::Service> for $serv {
69            fn from(v: $crate::types::reference::Service) -> Self {
70                Self(v)
71            }
72        }
73        impl $serv {
74            pub fn new(principal: $crate::Principal) -> Self {
75                $serv($crate::types::reference::Service { principal })
76            }
77        }
78    }
79}
80
81impl CandidType for Func {
82    fn _ty() -> Type {
83        panic!("Cannot use Func directly. Use `define_function!` macro instead.")
84    }
85    fn idl_serialize<S>(&self, serializer: S) -> Result<(), S::Error>
86    where
87        S: Serializer,
88    {
89        serializer.serialize_function(self.principal.as_slice(), &self.method)
90    }
91}
92impl CandidType for Service {
93    fn _ty() -> Type {
94        panic!("Cannot use Service directly. Use `define_service!` macro instead.")
95    }
96    fn idl_serialize<S>(&self, serializer: S) -> Result<(), S::Error>
97    where
98        S: Serializer,
99    {
100        serializer.serialize_principal(self.principal.as_slice())
101    }
102}
103
104/// A [`Visitor`] to extract [`Func`]s.
105pub struct FuncVisitor;
106
107impl Visitor<'_> for FuncVisitor {
108    type Value = Func;
109    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
110        formatter.write_str("Func value")
111    }
112    fn visit_byte_buf<E: de::Error>(self, bytes: Vec<u8>) -> Result<Func, E> {
113        if bytes[0] != 5u8 {
114            return Err(de::Error::custom("not func"));
115        }
116        let mut bytes = &bytes[1..];
117        let len = leb128::read::unsigned(&mut bytes).map_err(E::custom)? as usize;
118        let mut buf = vec![0; len];
119        bytes.read_exact(&mut buf).map_err(E::custom)?;
120        let method = String::from_utf8(buf).map_err(E::custom)?;
121        let principal = Principal::try_from(bytes).map_err(E::custom)?;
122        Ok(Func { principal, method })
123    }
124}
125
126impl<'de> Deserialize<'de> for Func {
127    fn deserialize<D>(deserializer: D) -> Result<Func, D::Error>
128    where
129        D: serde::Deserializer<'de>,
130    {
131        deserializer.deserialize_any(FuncVisitor)
132    }
133}
134
135impl<'de> Deserialize<'de> for Service {
136    fn deserialize<D>(deserializer: D) -> Result<Service, D::Error>
137    where
138        D: serde::Deserializer<'de>,
139    {
140        struct ServVisitor;
141        impl Visitor<'_> for ServVisitor {
142            type Value = Service;
143            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
144                formatter.write_str("Service value")
145            }
146            fn visit_byte_buf<E: de::Error>(self, bytes: Vec<u8>) -> Result<Service, E> {
147                if bytes[0] != 4u8 {
148                    return Err(de::Error::custom("not service"));
149                }
150                let bytes = &bytes[1..];
151                let principal = Principal::try_from(bytes).map_err(E::custom)?;
152                Ok(Service { principal })
153            }
154        }
155        deserializer.deserialize_any(ServVisitor)
156    }
157}