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}