Skip to content

Commit 83b1695

Browse files
committed
Add iterator methods to Result
This involved fixing the defn of iter::Once as well.
1 parent d044640 commit 83b1695

File tree

3 files changed

+108
-5
lines changed

3 files changed

+108
-5
lines changed

iter/once.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,24 @@ class [[sus_trivial_abi]] Once : public IteratorBase<Item> {
3434
Once(Option<Item>&& single) : single_(::sus::move(single)) {}
3535

3636
private:
37+
template <class U>
38+
friend inline Iterator<Once<U>> once(Option<U>&& single) noexcept
39+
requires(std::is_move_constructible_v<U>);
40+
41+
static Iterator<Once> with_option(Option<Item>&& single) {
42+
return Iterator<Once>(static_cast<Option<Item>&&>(single));
43+
}
44+
3745
RelocatableStorage<Item> single_;
3846

39-
sus_class_maybe_trivial_relocatable_types(unsafe_fn, decltype(single_));
47+
sus_class_assert_trivial_relocatable_types(unsafe_fn, decltype(single_));
4048
};
4149

4250
template <class Item>
43-
inline Once<Item> once(Option<Item>&& single)
51+
inline Iterator<Once<Item>> once(Option<Item>&& single) noexcept
4452
requires(std::is_move_constructible_v<Item>)
4553
{
46-
return Once(::sus::move(single));
54+
return Once<Item>::with_option(::sus::move(single));
4755
}
4856

4957
} // namespace sus::iter

result/result.h

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include "assertions/check.h"
3131
#include "assertions/unreachable.h"
32+
#include "iter/once.h"
3233
#include "marker/unsafe.h"
3334
#include "mem/mref.h"
3435
#include "mem/relocate.h"
@@ -38,6 +39,9 @@
3839

3940
namespace sus::result {
4041

42+
using sus::iter::Iterator;
43+
using sus::iter::Once;
44+
4145
/// The representation of an Result's state, which can either be #Ok to
4246
/// represent it has a success value, or #Err for when it is holding an error
4347
/// value.
@@ -227,7 +231,9 @@ class Result {
227231
switch (state_) {
228232
case IsOk:
229233
switch (state_ = replace(mref(o.state_), IsMoved)) {
230-
case IsOk: mem::replace_and_discard(mref(ok_), static_cast<T&&>(o.ok_)); break;
234+
case IsOk:
235+
mem::replace_and_discard(mref(ok_), static_cast<T&&>(o.ok_));
236+
break;
231237
case IsErr:
232238
ok_.~T();
233239
new (&err_) E(static_cast<E&&>(o.err_));
@@ -237,7 +243,9 @@ class Result {
237243
break;
238244
case IsErr:
239245
switch (state_ = replace(mref(o.state_), IsMoved)) {
240-
case IsErr: mem::replace_and_discard(mref(err_), static_cast<E&&>(o.err_)); break;
246+
case IsErr:
247+
mem::replace_and_discard(mref(err_), static_cast<E&&>(o.err_));
248+
break;
241249
case IsOk:
242250
err_.~T();
243251
new (&ok_) T(static_cast<T&&>(o.ok_));
@@ -366,6 +374,34 @@ class Result {
366374
return take_and_destruct(unsafe_fn, mref(err_));
367375
}
368376

377+
constexpr Iterator<Once<const T&>> iter() const& noexcept {
378+
check(state_ != IsMoved);
379+
if (state_ == IsOk)
380+
return sus::iter::once(Option<const T&>::some(ok_));
381+
else
382+
return sus::iter::once(Option<const T&>::none());
383+
}
384+
Iterator<Once<const T&>> iter() const&& = delete;
385+
386+
constexpr Iterator<Once<T&>> iter_mut() & noexcept {
387+
check(state_ != IsMoved);
388+
if (state_ == IsOk)
389+
return sus::iter::once(Option<T&>::some(mref(ok_)));
390+
else
391+
return sus::iter::once(Option<T&>::none());
392+
}
393+
394+
constexpr Iterator<Once<T>> into_iter() && noexcept {
395+
check(state_ != IsMoved);
396+
if (replace(mref(state_), IsMoved) == IsOk) {
397+
return sus::iter::once(
398+
Option<T>::some(take_and_destruct(unsafe_fn, mref(ok_))));
399+
} else {
400+
err_.~E();
401+
return sus::iter::once(Option<T>::none());
402+
}
403+
}
404+
369405
private:
370406
enum WithOkType { WithOk };
371407
constexpr inline Result(WithOkType, const T& t) noexcept

result/result_unittest.cc

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include "result/result.h"
2323

2424
#include "mem/move.h"
25+
#include "iter/once.h"
26+
#include "iter/iterator.h"
2527
#include "num/types.h"
2628
#include "third_party/googletest/googletest/include/gtest/gtest.h"
2729

@@ -230,4 +232,61 @@ TEST(Result, MoveAfterNonTrivialMove) {
230232
EXPECT_DEATH([[maybe_unused]] auto r2 = sus::move(r), "");
231233
}
232234

235+
TEST(Result, Iter) {
236+
auto x = Result<i32, u8>::with_err(2_u8);
237+
for ([[maybe_unused]] auto i : x.iter()) {
238+
ADD_FAILURE();
239+
}
240+
241+
int count = 0;
242+
auto y = Result<i32, u8>::with(-4_i32);
243+
for (auto& i : y.iter()) {
244+
static_assert(std::is_same_v<decltype(i), const i32&>, "");
245+
EXPECT_EQ(i, -4_i32);
246+
++count;
247+
}
248+
EXPECT_EQ(count, 1);
249+
}
250+
251+
TEST(Result, IterMut) {
252+
auto x = Result<i32, u8>::with_err(2_u8);
253+
for ([[maybe_unused]] auto i : x.iter_mut()) {
254+
ADD_FAILURE();
255+
}
256+
257+
int count = 0;
258+
auto y = Result<i32, u8>::with(-3_i32);
259+
for (auto& i : y.iter_mut()) {
260+
static_assert(std::is_same_v<decltype(i), i32&>, "");
261+
EXPECT_EQ(i, -3_i32);
262+
i += 1;
263+
++count;
264+
}
265+
EXPECT_EQ(sus::move(y).unwrap(), -2_i32);
266+
}
267+
268+
struct MoveOnly {
269+
explicit MoveOnly(int i) : i(i) {}
270+
MoveOnly(MoveOnly&& o) : i(o.i) {}
271+
void operator=(MoveOnly&& o) { i = o.i; }
272+
273+
int i;
274+
};
275+
276+
TEST(Result, IntoIter) {
277+
auto x = Result<i32, u8>::with_err(2_u8);
278+
for ([[maybe_unused]] auto i : x.iter_mut()) {
279+
ADD_FAILURE();
280+
}
281+
282+
int count = 0;
283+
auto y = Result<MoveOnly, u8>::with(MoveOnly(-3));
284+
for (auto m : sus::move(y).into_iter()) {
285+
static_assert(std::is_same_v<decltype(m), MoveOnly>, "");
286+
EXPECT_EQ(m.i, -3);
287+
++count;
288+
}
289+
EXPECT_EQ(count, 1);
290+
}
291+
233292
} // namespace

0 commit comments

Comments
 (0)