Skip to content

Commit 8419e5a

Browse files
Better reference handling for rfl::Result
1 parent 77dadea commit 8419e5a

File tree

1 file changed

+58
-37
lines changed

1 file changed

+58
-37
lines changed

include/rfl/Result.hpp

Lines changed: 58 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -119,19 +119,19 @@ class Result {
119119

120120
/// Monadic operation - F must be a function of type T -> Result<U>.
121121
template <class F>
122-
auto and_then(const F& _f) {
122+
auto and_then(F&& _f) && {
123123
/// Result_U is expected to be of type Result<U>.
124124
using Result_U = typename std::invoke_result<F, T>::type;
125125
if (success_) {
126-
return Result_U(_f(std::forward<T>(get_t())));
126+
return Result_U(_f(std::move(*this).get_t()));
127127
} else {
128-
return Result_U(std::forward<Error>(get_err()));
128+
return Result_U(std::move(*this).get_err());
129129
}
130130
}
131131

132132
/// Monadic operation - F must be a function of type T -> Result<U>.
133133
template <class F>
134-
auto and_then(const F& _f) const {
134+
auto and_then(const F& _f) const& {
135135
/// Result_U is expected to be of type Result<U>.
136136
using Result_U = typename std::invoke_result<F, T>::type;
137137
if (success_) {
@@ -146,11 +146,15 @@ class Result {
146146

147147
/// Allows access to the underlying value. Careful: Will result in undefined
148148
/// behavior, if the result contains an error.
149-
T& operator*() noexcept { return get_t(); }
149+
T&& operator*() && noexcept { return std::move(*this).get_t(); }
150+
151+
/// Allows access to the underlying value. Careful: Will result in undefined
152+
/// behavior, if the result contains an error.
153+
T& operator*() & noexcept { return get_t(); }
150154

151155
/// Allows read access to the underlying value. Careful: Will result in
152156
/// undefined behavior, if the result contains an error.
153-
const T& operator*() const noexcept { return get_t(); }
157+
const T& operator*() const& noexcept { return get_t(); }
154158

155159
/// Assigns the underlying object.
156160
Result<T>& operator=(const Result<T>& _other) {
@@ -180,6 +184,7 @@ class Result {
180184
new (&get_err()) Error(_err.error());
181185
return *this;
182186
}
187+
183188
Result<T>& operator=(const Unexpected<Error>& _err) noexcept {
184189
destroy();
185190
success_ = false;
@@ -199,18 +204,18 @@ class Result {
199204
/// Expects a function that takes of type Error -> Result<T> and returns
200205
/// Result<T>.
201206
template <class F>
202-
Result<T> or_else(const F& _f) {
207+
Result<T> or_else(const F& _f) && {
203208
if (success_) {
204-
return std::forward<T>(get_t());
209+
return std::move(*this).get_t();
205210
} else {
206-
return _f(std::forward<Error>(get_err()));
211+
return _f(std::move(*this).get_err());
207212
}
208213
}
209214

210215
/// Expects a function that takes of type Error -> Result<T> and returns
211216
/// Result<T>.
212217
template <class F>
213-
Result<T> or_else(const F& _f) const {
218+
Result<T> or_else(const F& _f) const& {
214219
if (success_) {
215220
return get_t();
216221
} else {
@@ -220,19 +225,19 @@ class Result {
220225

221226
/// Functor operation - F must be a function of type T -> U.
222227
template <class F>
223-
auto transform(const F& _f) {
228+
auto transform(const F& _f) && {
224229
/// Result_U is expected to be of type Result<U>.
225-
using U = typename std::invoke_result<F, T>::type;
230+
using U = std::invoke_result_t<F, T>;
226231
if (success_) {
227-
return rfl::Result<U>(_f(std::forward<T>(get_t())));
232+
return rfl::Result<U>(_f(std::move(*this).get_t()));
228233
} else {
229-
return rfl::Result<U>(rfl::Unexpected(std::forward<Error>(get_err())));
234+
return rfl::Result<U>(rfl::Unexpected(std::move(*this).get_err()));
230235
}
231236
}
232237

233238
/// Functor operation - F must be a function of type T -> U.
234239
template <class F>
235-
auto transform(const F& _f) const {
240+
auto transform(const F& _f) const& {
236241
/// Result_U is expected to be of type Result<U>.
237242
using U = typename std::invoke_result<F, T>::type;
238243
if (success_) {
@@ -244,17 +249,17 @@ class Result {
244249

245250
/// Returns the value if the result does not contain an error, throws an
246251
/// exceptions if not. Similar to .unwrap() in Rust.
247-
T& value() {
252+
T&& value() && {
248253
if (success_) {
249-
return get_t();
254+
return std::move(*this).get_t();
250255
} else {
251256
throw std::runtime_error(get_err().what());
252257
}
253258
}
254259

255260
/// Returns the value if the result does not contain an error, throws an
256261
/// exceptions if not. Similar to .unwrap() in Rust.
257-
const T& value() const {
262+
const T& value() const& {
258263
if (success_) {
259264
return get_t();
260265
} else {
@@ -263,64 +268,72 @@ class Result {
263268
}
264269

265270
/// Returns the value or a default.
266-
T value_or(T&& _default) noexcept {
271+
T&& value_or(T&& _default) && noexcept {
267272
if (success_) {
268-
return std::forward<T>(get_t());
273+
return std::move(*this).get_t();
269274
} else {
270275
return std::forward<T>(_default);
271276
}
272277
}
273278

274279
/// Returns the value or a default.
275-
T value_or(const T& _default) const noexcept {
280+
T value_or(const T& _default) const& noexcept {
276281
if (success_) {
277282
return get_t();
278283
} else {
279284
return _default;
280285
}
281286
}
282287

283-
// As specified by the standard :
284-
// https://en.cppreference.com/w/cpp/utility/expected
285-
// Observers
286288
template <class G = rfl::Error>
287-
rfl::Error error_or(G&& _default) const& {
289+
rfl::Error error_or(G&& _default) && {
288290
if (success_) {
289-
return _default;
291+
return std::forward<G>(_default);
290292
} else {
291-
return get_err();
293+
return std::move(*this).get_err();
292294
}
293295
}
296+
297+
// As specified by the standard :
298+
// https://en.cppreference.com/w/cpp/utility/expected
299+
// Observers
294300
template <class G = rfl::Error>
295-
rfl::Error error_or(G&& _default) && {
301+
rfl::Error error_or(G&& _default) const& {
296302
if (success_) {
297-
return _default;
303+
return std::forward<G>(_default);
298304
} else {
299305
return get_err();
300306
}
301307
}
308+
302309
bool has_value() const noexcept { return success_; }
310+
303311
const Error& error() const& {
304312
if (success_) throw std::runtime_error("Expected does not contain value");
305313
return get_err();
306314
}
307-
Error& error() & {
315+
316+
Error& error() && {
308317
if (success_) throw std::runtime_error("Expected does not contain value");
309-
return get_err();
318+
return std::move(*this).get_err();
310319
}
320+
311321
T* operator->() noexcept { return &get_t(); }
322+
312323
const T* operator->() const noexcept { return &get_t(); }
324+
313325
template <class F>
314326
rfl::Result<T> transform_error(F&& f) && {
315327
static_assert(
316328
std::is_same<std::invoke_result_t<F, rfl::Error>, rfl::Error>(),
317329
"A function passed to transform_error must return an error.");
318330
if (!has_value()) {
319-
return rfl::Result<T>{std::invoke(f, std::move(get_err()))};
331+
return rfl::Result<T>{std::invoke(f, std::move(*this).get_err())};
320332
} else {
321-
return rfl::Result<T>{std::move(value())};
333+
return rfl::Result<T>{std::move(*this).value()};
322334
}
323335
}
336+
324337
template <class F>
325338
rfl::Result<T> transform_error(F&& f) const& {
326339
static_assert(
@@ -352,19 +365,27 @@ class Result {
352365
}
353366
}
354367

355-
T& get_t() noexcept {
368+
T&& get_t() && noexcept {
369+
return std::move(*std::launder(reinterpret_cast<T*>(t_or_err_.data())));
370+
}
371+
372+
T& get_t() & noexcept {
356373
return *std::launder(reinterpret_cast<T*>(t_or_err_.data()));
357374
}
358375

359-
const T& get_t() const noexcept {
376+
const T& get_t() const& noexcept {
360377
return *std::launder(reinterpret_cast<const T*>(t_or_err_.data()));
361378
}
362379

363-
Error& get_err() noexcept {
380+
Error&& get_err() && noexcept {
381+
return std::move(*std::launder(reinterpret_cast<Error*>(t_or_err_.data())));
382+
}
383+
384+
Error& get_err() & noexcept {
364385
return *std::launder(reinterpret_cast<Error*>(t_or_err_.data()));
365386
}
366387

367-
const Error& get_err() const noexcept {
388+
const Error& get_err() const& noexcept {
368389
return *std::launder(reinterpret_cast<const Error*>(t_or_err_.data()));
369390
}
370391

0 commit comments

Comments
 (0)