ink_primitives/sol/result.rs
1// Copyright (C) ink! contributors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use ink_prelude::vec::Vec;
16
17use crate::sol::{
18 Error,
19 SolDecode,
20 SolEncode,
21 SolErrorDecode,
22 SolErrorEncode,
23};
24
25impl<'a, T, E> SolEncode<'a> for Result<T, E>
26where
27 T: SolEncode<'a>,
28 E: SolErrorEncode,
29{
30 // NOTE: Not actually used for encoding because of `encode` override below.
31 // However, it's used for metadata generation, so the unwrapped type is used.
32 type SolType = <T as SolEncode<'a>>::SolType;
33
34 fn encode(&'a self) -> Vec<u8> {
35 match self {
36 Ok(val) => val.encode(),
37 Err(err) => err.encode(),
38 }
39 }
40
41 // NOTE: Not actually used for encoding because of `encode` override above.
42 fn to_sol_type(&self) -> Self::SolType {
43 unimplemented!("Use the `encode` function directly instead.")
44 }
45}
46
47/// Solidity ABI decode result data.
48// Note: We define and implement this here (e.g. as opposed to an implementation
49// in `ink_env`) because we need 2 generic implementations for `T: SolEncode` and
50// `Result<T: SolEncode, E>` which `rustc` only allows if `Result<T, E>: !SolEncode`
51// (i.e. `Result<T, E>` doesn't implement `SolEncode`). The latter negative condition is
52// only allowed in this crate (because `SolEncode` is defined in this crate) as per Rust's
53// coherence/orphan rules.
54//
55// Ref: <https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules>
56pub trait SolResultDecode {
57 /// Solidity ABI decode result data into this type.
58 fn decode(data: &[u8], did_revert: bool) -> Result<Self, SolResultDecodeError>
59 where
60 Self: Sized;
61}
62
63/// Error representing reason for failing to decode Solidity ABI encoded result data.
64#[derive(Debug, Copy, Clone, PartialEq, Eq)]
65pub enum SolResultDecodeError {
66 /// Tried to decode revert/error data into a non-Result type.
67 NonResultFromRevert,
68 /// A general decoding error.
69 Decode,
70}
71
72impl From<Error> for SolResultDecodeError {
73 fn from(_: Error) -> Self {
74 SolResultDecodeError::Decode
75 }
76}
77
78impl<T> SolResultDecode for T
79where
80 T: SolDecode,
81{
82 fn decode(data: &[u8], did_revert: bool) -> Result<Self, SolResultDecodeError>
83 where
84 Self: Sized,
85 {
86 if did_revert {
87 Err(SolResultDecodeError::NonResultFromRevert)
88 } else {
89 Ok(T::decode(data)?)
90 }
91 }
92}
93
94impl<T, E> SolResultDecode for Result<T, E>
95where
96 T: SolDecode,
97 E: SolErrorDecode,
98{
99 fn decode(data: &[u8], did_revert: bool) -> Result<Self, SolResultDecodeError>
100 where
101 Self: Sized,
102 {
103 if did_revert {
104 Ok(E::decode(data).map(|err| Err(err))?)
105 } else {
106 Ok(T::decode(data).map(|val| Ok(val))?)
107 }
108 }
109}