1
// Copyright © 2017-2020 Trust Wallet.
2
//
3
// This file is part of Trust. The full Trust copyright notice, including
4
// terms governing use, modification, and redistribution, is contained in the
5
// file LICENSE at the root of the source code distribution tree.
6

7
#pragma once
8

9
#include <optional>
10
#include <string>
11
#include <type_traits>
12

13
namespace TW {
14

15
namespace Types {
16
template <typename T>
17 1
struct Success {
18
    Success(const T& val) : val(val) {}
19 1
    Success(T&& val) : val(std::move(val)) {}
20

21
    T val;
22
};
23

24
template <>
25
struct Success<void> {};
26

27
template <typename E>
28 1
struct Failure {
29
    Failure(const E& val) : val(val) {}
30 1
    Failure(E&& val) : val(std::move(val)) {}
31

32
    E val;
33
};
34
} // namespace Types
35

36
template <typename T, typename E = std::string>
37
struct Result {
38
  private:
39
    static_assert(!std::is_same<E, void>::value, "void error type is not allowed");
40
    static constexpr size_t Size = sizeof(T) > sizeof(E) ? sizeof(T) : sizeof(E);
41
    static constexpr size_t Align = sizeof(T) > sizeof(E) ? alignof(T) : alignof(E);
42
    using Storage = typename std::aligned_storage<Size, Align>::type;
43

44
    /// Wether the operation succeeded.
45
    bool success_;
46
    Storage storage_;
47

48
  public:
49
    /// Initializes a success result with a payload.
50 1
    Result(Types::Success<T> payload) : success_(true) { new (&storage_) T(payload.val); }
51

52
    /// Initializes a failure result.
53 1
    Result(Types::Failure<E> error) : success_(false) { new (&storage_) E(error.val); }
54

55
    Result(const Result& other) : success_(other.success_) {
56
        if (success_) {
57
            new (&storage_) T(other.get<T>());
58
        } else {
59
            new (&storage_) E(other.get<E>());
60
        }
61
    }
62

63
    Result& operator=(const Result& other) {
64
        if (success_) {
65
            get<T>().~T();
66
        } else {
67
            get<E>().~E();
68
        }
69

70
        success_ = other.success_;
71
        if (success_) {
72
            new (&storage_) T(other.get<T>());
73
        } else {
74
            new (&storage_) E(other.get<E>());
75
        }
76
    }
77

78
    Result(Result&& other) {
79
        if (success_) {
80
            new (&storage_) T(other.get<T>());
81
        } else {
82
            new (&storage_) E(other.get<E>());
83
        }
84
    }
85

86
    Result& operator=(Result&& other) {
87
        if (success_) {
88
            get<T>().~T();
89
        } else {
90
            get<E>().~E();
91
        }
92

93
        success_ = other.success_;
94
        if (success_) {
95
            new (&storage_) T(std::move(other.get<T>()));
96
        } else {
97
            new (&storage_) E(std::move(other.get<E>()));
98
        }
99
    }
100

101 1
    ~Result() {
102 1
        if (success_)
103 1
            get<T>().~T();
104
        else
105 1
            get<E>().~E();
106
    }
107

108
    bool isSuccess() const { return success_; }
109

110
    bool isFailure() const { return !success_; }
111

112
    /// Returns the contained payload.
113
    ///
114
    /// The behavior is undefined if this result is a failure.
115 1
    T payload() const { return get<T>(); }
116

117
    /// Returns the contained error.
118
    ///
119
    /// The behavior is undefined if this result is a success.
120 1
    E error() const { return get<E>(); }
121

122
    /// Returns a new success result with the given payloadd.
123 1
    static Result<T, E> success(T&& val) { return Result(Types::Success<T>(std::forward<T>(val))); }
124

125
    /// Returns a new failure result with the given error.
126 1
    static Result<T, E> failure(E&& val) { return Result(Types::Failure<E>(std::forward<E>(val))); }
127

128 1
    operator bool() const { return success_; }
129

130
  private:
131
    template <typename U>
132 1
    const U& get() const {
133 1
        return *reinterpret_cast<const U*>(&storage_);
134
    }
135

136
    template <typename U>
137 1
    U& get() {
138 1
        return *reinterpret_cast<U*>(&storage_);
139
    }
140
};
141

142
template <typename E>
143 1
struct Result<void, E> {
144
  private:
145
    /// Wether the operation succeeded.
146
    bool success_;
147
    std::optional<E> error_;
148

149
  public:
150
    /// Initializes a success result with a payload.
151 1
    Result(Types::Success<void> payload) : success_(true), error_() {}
152

153
    /// Initializes a failure result.
154 1
    Result(Types::Failure<E> error) : success_(false), error_(error.val) {}
155

156
    bool isSuccess() const { return success_; }
157

158
    bool isFailure() const { return !success_; }
159

160
    /// Returns the contained error.
161
    ///
162
    /// The behavior is undefined if this result is a success.
163 1
    E error() const { return *error_; }
164

165
    /// Returns a new success result with no payloadd.
166 1
    static inline Result<void> success() { return Result(Types::Success<void>()); }
167

168
    /// Returns a new failure result with the given error.
169 1
    static Result<void, E> failure(E&& val) {
170 1
        return Result(Types::Failure<E>(std::forward<E>(val)));
171
    }
172

173 1
    operator bool() const { return success_; }
174
};
175

176
} // namespace TW

Read our documentation on viewing source code .

Loading