diff --git a/rust/candid_parser/src/bindings/rust.rs b/rust/candid_parser/src/bindings/rust.rs index facad992..481b05f9 100644 --- a/rust/candid_parser/src/bindings/rust.rs +++ b/rust/candid_parser/src/bindings/rust.rs @@ -720,6 +720,7 @@ pub enum TypePath { Vec, RecordField(String), VariantField(String), + ResultField(String), Func(String), Init, } @@ -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(), @@ -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)); diff --git a/rust/candid_parser/tests/assets/example.did b/rust/candid_parser/tests/assets/example.did index a0a865d1..4b5eb26c 100644 --- a/rust/candid_parser/tests/assets/example.did +++ b/rust/candid_parser/tests/assets/example.did @@ -9,13 +9,13 @@ 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 } }; service server : { f1 : (list, test: blob, opt bool) -> () oneway; g1 : (my_type, List, opt List, nested) -> (int, broker) 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; } diff --git a/rust/candid_parser/tests/assets/ok/example.d.ts b/rust/candid_parser/tests/assets/ok/example.d.ts index d7b7c8e3..9c047118 100644 --- a/rust/candid_parser/tests/assets/ok/example.d.ts +++ b/rust/candid_parser/tests/assets/ok/example.d.ts @@ -25,8 +25,8 @@ export interface nested { _42_ : 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>; @@ -55,7 +55,7 @@ export interface _SERVICE { [ [] | [a], [] | [b], - { 'Ok' : null } | + { 'Ok' : { 'result' : string } } | { 'Err' : { 'a' : null } | { 'b' : null } }, ] >, diff --git a/rust/candid_parser/tests/assets/ok/example.did b/rust/candid_parser/tests/assets/ok/example.did index d2063d17..75171d77 100644 --- a/rust/candid_parser/tests/assets/ok/example.did +++ b/rust/candid_parser/tests/assets/ok/example.did @@ -19,7 +19,7 @@ type nested = record { 42 : nat; }; 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) -> (); @@ -40,6 +40,6 @@ service : { x : (a, b) -> ( opt a, opt b, - variant { Ok; Err : variant { a; b } }, + variant { Ok : record { result : text }; Err : variant { a; b } }, ) composite_query; } diff --git a/rust/candid_parser/tests/assets/ok/example.js b/rust/candid_parser/tests/assets/ok/example.js index 7004ca7e..46448e7c 100644 --- a/rust/candid_parser/tests/assets/ok/example.js +++ b/rust/candid_parser/tests/assets/ok/example.js @@ -57,7 +57,10 @@ export const idlFactory = ({ IDL }) => { [], ), }); - const res = IDL.Variant({ 'Ok' : IDL.Nat, 'Err' : IDL.Empty }); + 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], @@ -94,7 +97,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 }), }), ], diff --git a/rust/candid_parser/tests/assets/ok/example.mo b/rust/candid_parser/tests/assets/ok/example.mo index 9d87e459..2d27fa3d 100644 --- a/rust/candid_parser/tests/assets/ok/example.mo +++ b/rust/candid_parser/tests/assets/ok/example.mo @@ -29,7 +29,7 @@ module { _42_ : Nat; }; 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 (); @@ -51,7 +51,7 @@ module { x : shared composite query (a, b) -> async ( ?a, ?b, - { #Ok; #Err : { #a; #b } }, + { #Ok : { result : Text }; #Err : { #a; #b } }, ); } } diff --git a/rust/candid_parser/tests/assets/ok/example.rs b/rust/candid_parser/tests/assets/ok/example.rs index 84c5ae02..8ea7be97 100644 --- a/rust/candid_parser/tests/assets/ok/example.rs +++ b/rust/candid_parser/tests/assets/ok/example.rs @@ -83,7 +83,9 @@ 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; +#[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, Res, @@ -91,6 +93,8 @@ candid::define_function!(pub(crate) F : (MyList, FArg1) -> ( #[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); @@ -116,7 +120,7 @@ impl Service { pub async fn i(&self, arg0: MyList, arg1: FArg1) -> Result<(Option,Res,)> { ic_cdk::call(self.0, "i", (arg0,arg1,)).await } - pub async fn x(&self, arg0: A, arg1: B) -> Result<(Option,Option,std::result::Result<(), Error>,)> { + pub async fn x(&self, arg0: A, arg1: B) -> Result<(Option,Option,std::result::Result,)> { ic_cdk::call(self.0, "x", (arg0,arg1,)).await } }