Skip to content

Commit

Permalink
fix result struct binding (#559)
Browse files Browse the repository at this point in the history
* fix result struct binding

* nested result test
  • Loading branch information
chenyan-dfinity authored Jun 21, 2024
1 parent 223fe03 commit 1caba61
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 22 deletions.
15 changes: 12 additions & 3 deletions rust/candid_parser/src/bindings/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@ pub enum TypePath {
Vec,
RecordField(String),
VariantField(String),
ResultField(String),
Func(String),
Init,
}
Expand All @@ -728,7 +729,9 @@ fn path_to_var(path: &[TypePath]) -> String {
.iter()
.map(|node| match node {
TypePath::Id(id) => id.as_str(),
TypePath::RecordField(f) | TypePath::VariantField(f) => f.as_str(),
TypePath::RecordField(f) | TypePath::VariantField(f) | TypePath::ResultField(f) => {
f.as_str()
}
TypePath::Opt => "inner",
TypePath::Vec => "item",
TypePath::Func(id) => id.as_str(),
Expand Down Expand Up @@ -801,13 +804,19 @@ impl<'a> NominalState<'a> {
}
}
TypeInner::Variant(fs) => {
if matches!(path.last(), None | Some(TypePath::Id(_))) || as_result(fs).is_some() {
let is_result = as_result(fs).is_some();
if matches!(path.last(), None | Some(TypePath::Id(_))) || is_result {
let fs: Vec<_> = fs
.iter()
.map(|Field { id, ty }| {
let lab = id.to_string();
let old = self.state.push_state(&StateElem::Label(&lab));
path.push(TypePath::VariantField(id.to_string()));
if is_result {
// so that inner record gets a new name
path.push(TypePath::ResultField(id.to_string()));
} else {
path.push(TypePath::VariantField(id.to_string()));
}
let ty = self.nominalize(env, path, ty);
path.pop();
self.state.pop_state(old, StateElem::Label(&lab));
Expand Down
7 changes: 4 additions & 3 deletions rust/candid_parser/tests/assets/example.did
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ type broker = service {
(service {up:() -> (); current:() -> (nat32)});
};
type nested = record { nat; nat; record {nat;int;}; record { nat; 0x2a:nat; nat8; }; 42:nat; 40:nat; variant{ A; 0x2a; B; C }; };
type res = variant { Ok: nat; Err: empty };
type res = variant { Ok: record{int;nat}; Err: record{ error: text } };
type nested_res = variant { Ok: variant { Ok; Err }; Err: variant { Ok: record { content: text }; Err: record {int} } };

service server : {
f1 : (list, test: blob, opt bool) -> () oneway;
g1 : (my_type, List, opt List, nested) -> (int, broker) query;
g1 : (my_type, List, opt List, nested) -> (int, broker, nested_res) query;
h : (vec opt text, variant { A: nat; B: opt text }, opt List) -> (record { id: nat; 0x2a: record {} });
i : f;
x : (a,b) -> (opt a, opt b, variant { Ok; Err: variant {a;b} }) composite_query;
x : (a,b) -> (opt a, opt b, variant { Ok: record { result: text }; Err: variant {a;b} }) composite_query;
}

13 changes: 9 additions & 4 deletions rust/candid_parser/tests/assets/ok/example.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ export interface nested {
{ 'C' : null },
_42_ : bigint,
}
export type nested_res = { 'Ok' : { 'Ok' : null } | { 'Err' : null } } |
{ 'Err' : { 'Ok' : { 'content' : string } } | { 'Err' : [bigint] } };
export interface node { 'head' : bigint, 'tail' : list }
export type res = { 'Ok' : bigint } |
{ 'Err' : never };
export type res = { 'Ok' : [bigint, bigint] } |
{ 'Err' : { 'error' : string } };
export interface s { 'f' : t, 'g' : ActorMethod<[list], [B, tree, stream]> }
export type stream = [] | [{ 'head' : bigint, 'next' : [Principal, string] }];
export type t = ActorMethod<[Principal], undefined>;
Expand All @@ -39,7 +41,10 @@ export interface _SERVICE {
'f' : t,
'f1' : ActorMethod<[list, Uint8Array | number[], [] | [boolean]], undefined>,
'g' : ActorMethod<[list], [B, tree, stream]>,
'g1' : ActorMethod<[my_type, List, [] | [List], nested], [bigint, Principal]>,
'g1' : ActorMethod<
[my_type, List, [] | [List], nested],
[bigint, Principal, nested_res]
>,
'h' : ActorMethod<
[
Array<[] | [string]>,
Expand All @@ -55,7 +60,7 @@ export interface _SERVICE {
[
[] | [a],
[] | [b],
{ 'Ok' : null } |
{ 'Ok' : { 'result' : string } } |
{ 'Err' : { 'a' : null } | { 'b' : null } },
]
>,
Expand Down
10 changes: 7 additions & 3 deletions rust/candid_parser/tests/assets/ok/example.did
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ type nested = record {
41 : variant { 42; A; B; C };
42 : nat;
};
type nested_res = variant {
Ok : variant { Ok; Err };
Err : variant { Ok : record { content : text }; Err : record { int } };
};
type node = record { head : nat; tail : list };
type res = variant { Ok : nat; Err : empty };
type res = variant { Ok : record { int; nat }; Err : record { error : text } };
type s = service { f : t; g : (list) -> (B, tree, stream) };
type stream = opt record { head : nat; next : func () -> (stream) query };
type t = func (s) -> ();
Expand All @@ -32,14 +36,14 @@ service : {
f : t;
f1 : (list, blob, opt bool) -> () oneway;
g : (list) -> (B, tree, stream);
g1 : (my_type, List, opt List, nested) -> (int, broker) query;
g1 : (my_type, List, opt List, nested) -> (int, broker, nested_res) query;
h : (vec opt text, variant { A : nat; B : opt text }, opt List) -> (
record { 42 : record {}; id : nat },
);
i : f;
x : (a, b) -> (
opt a,
opt b,
variant { Ok; Err : variant { a; b } },
variant { Ok : record { result : text }; Err : variant { a; b } },
) composite_query;
}
16 changes: 13 additions & 3 deletions rust/candid_parser/tests/assets/ok/example.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,17 @@ export const idlFactory = ({ IDL }) => {
[],
),
});
const res = IDL.Variant({ 'Ok' : IDL.Nat, 'Err' : IDL.Empty });
const nested_res = IDL.Variant({
'Ok' : IDL.Variant({ 'Ok' : IDL.Null, 'Err' : IDL.Null }),
'Err' : IDL.Variant({
'Ok' : IDL.Record({ 'content' : IDL.Text }),
'Err' : IDL.Tuple(IDL.Int),
}),
});
const res = IDL.Variant({
'Ok' : IDL.Tuple(IDL.Int, IDL.Nat),
'Err' : IDL.Record({ 'error' : IDL.Text }),
});
const f = IDL.Func(
[List, IDL.Func([IDL.Int32], [IDL.Int64], [])],
[IDL.Opt(List), res],
Expand All @@ -75,7 +85,7 @@ export const idlFactory = ({ IDL }) => {
'g' : IDL.Func([list], [B, tree, stream], []),
'g1' : IDL.Func(
[my_type, List, IDL.Opt(List), nested],
[IDL.Int, broker],
[IDL.Int, broker, nested_res],
['query'],
),
'h' : IDL.Func(
Expand All @@ -94,7 +104,7 @@ export const idlFactory = ({ IDL }) => {
IDL.Opt(a),
IDL.Opt(b),
IDL.Variant({
'Ok' : IDL.Null,
'Ok' : IDL.Record({ 'result' : IDL.Text }),
'Err' : IDL.Variant({ 'a' : IDL.Null, 'b' : IDL.Null }),
}),
],
Expand Down
14 changes: 11 additions & 3 deletions rust/candid_parser/tests/assets/ok/example.mo
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@ module {
_41_ : { #_42_ ; #A; #B; #C };
_42_ : Nat;
};
public type nested_res = {
#Ok : { #Ok; #Err };
#Err : { #Ok : { content : Text }; #Err : { _0_ : Int } };
};
public type node = { head : Nat; tail : list };
public type res = { #Ok : Nat; #Err : None };
public type res = { #Ok : (Int, Nat); #Err : { error : Text } };
public type s = actor { f : t; g : shared list -> async (B, tree, stream) };
public type stream = ?{ head : Nat; next : shared query () -> async stream };
public type t = shared s -> async ();
Expand All @@ -42,7 +46,11 @@ module {
f : t;
f1 : shared (list, Blob, ?Bool) -> ();
g : shared list -> async (B, tree, stream);
g1 : shared query (my_type, List, ?List, nested) -> async (Int, broker);
g1 : shared query (my_type, List, ?List, nested) -> async (
Int,
broker,
nested_res,
);
h : shared ([?Text], { #A : Nat; #B : ?Text }, ?List) -> async {
_42_ : {};
id : Nat;
Expand All @@ -51,7 +59,7 @@ module {
x : shared composite query (a, b) -> async (
?a,
?b,
{ #Ok; #Err : { #a; #b } },
{ #Ok : { result : Text }; #Err : { #a; #b } },
);
}
}
17 changes: 14 additions & 3 deletions rust/candid_parser/tests/assets/ok/example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,31 @@ candid::define_service!(pub(crate) Broker : {
"find" : candid::func!((String) -> (BrokerReturn));
});
#[derive(CandidType, Deserialize, Debug)]
pub(crate) struct NestedResErrOk { pub(crate) content: String }
pub(crate) type NestedRes = std::result::Result<
std::result::Result<(), ()>, std::result::Result<
NestedResErrOk, (candid::Int,)
>
>;
#[derive(CandidType, Deserialize, Debug)]
pub(crate) enum HArg1 { A(u128), B(Option<String>) }
#[derive(CandidType, Deserialize, Debug)]
pub(crate) struct HRet42 {}
#[derive(CandidType, Deserialize, Debug)]
pub(crate) struct HRet { pub(crate) _42_: HRet42, pub(crate) id: u128 }
candid::define_function!(pub(crate) FArg1 : (i32) -> (i64));
pub(crate) type Res = std::result::Result<u128, candid::Empty>;
#[derive(CandidType, Deserialize, Debug)]
pub(crate) struct ResErr { pub(crate) error: String }
pub(crate) type Res = std::result::Result<(candid::Int,u128,), ResErr>;
candid::define_function!(pub(crate) F : (MyList, FArg1) -> (
Option<MyList>,
Res,
));
#[derive(CandidType, Deserialize, Debug)]
pub(crate) enum A { #[serde(rename="a")] A, #[serde(rename="b")] B(B) }
#[derive(CandidType, Deserialize, Debug)]
pub(crate) struct XRet2Ok { pub(crate) result: String }
#[derive(CandidType, Deserialize, Debug)]
pub(crate) enum Error { #[serde(rename="a")] A, #[serde(rename="b")] B }

pub struct Service(pub Principal);
Expand All @@ -107,7 +118,7 @@ impl Service {
pub async fn g(&self, arg0: List) -> Result<(B,Tree,Stream,)> {
ic_cdk::call(self.0, "g", (arg0,)).await
}
pub async fn G11(&self, id: CanisterId, list: MyList, is_okay: Option<MyList>, arg3: Nested) -> Result<(i128,Broker,)> {
pub async fn G11(&self, id: CanisterId, list: MyList, is_okay: Option<MyList>, arg3: Nested) -> Result<(i128,Broker,NestedRes,)> {
ic_cdk::call(self.0, "g1", (id,list,is_okay,arg3,)).await
}
pub async fn h(&self, arg0: Vec<Option<String>>, arg1: HArg1, arg2: Option<MyList>) -> Result<(HRet,)> {
Expand All @@ -116,7 +127,7 @@ impl Service {
pub async fn i(&self, arg0: MyList, arg1: FArg1) -> Result<(Option<MyList>,Res,)> {
ic_cdk::call(self.0, "i", (arg0,arg1,)).await
}
pub async fn x(&self, arg0: A, arg1: B) -> Result<(Option<A>,Option<B>,std::result::Result<(), Error>,)> {
pub async fn x(&self, arg0: A, arg1: B) -> Result<(Option<A>,Option<B>,std::result::Result<XRet2Ok, Error>,)> {
ic_cdk::call(self.0, "x", (arg0,arg1,)).await
}
}
Expand Down

0 comments on commit 1caba61

Please sign in to comment.