Skip to content

Commit 9c6d1f1

Browse files
refactor: iteration methods on Option
1 parent 8f84785 commit 9c6d1f1

2 files changed

Lines changed: 70 additions & 1 deletion

File tree

src/main/java/net/marcellperger/mathexpr/util/rs/Option.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
import org.jetbrains.annotations.Contract;
55
import org.jetbrains.annotations.NotNull;
66

7+
import java.util.Collections;
8+
import java.util.Iterator;
79
import java.util.function.Consumer;
810
import java.util.function.Function;
911
import java.util.function.Predicate;
1012
import java.util.function.Supplier;
13+
import java.util.stream.Stream;
1114

12-
public sealed interface Option<T> {
15+
public sealed interface Option<T> extends Iterable<T> {
1316
record Some<T>(T value) implements Option<T> {
1417
@Contract(pure = true)
1518
@Override
@@ -95,4 +98,22 @@ default Option<T> inspectErr(Runnable noneFn) {
9598
if(isNone()) noneFn.run();
9699
return this;
97100
}
101+
102+
// .iter()-esque methods: why does Java have SO MANY - one is enough.
103+
default Stream<T> stream() {
104+
return mapOrElse(Stream::empty, Stream::of);
105+
}
106+
// Iterable automatically implements `spliterator()` for us
107+
@NotNull
108+
@Override
109+
default Iterator<T> iterator() {
110+
return switch (this) {
111+
case Some(T value) -> Util.singleItemIterator(value);
112+
case None() -> Collections.emptyIterator();
113+
};
114+
}
115+
@Override
116+
default void forEach(Consumer<? super T> action) {
117+
map(Util.consumerToFunction(action));
118+
}
98119
}

src/test/java/net/marcellperger/mathexpr/util/rs/OptionTest.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
import net.marcellperger.mathexpr.util.rs.Option.None;
66
import org.junit.jupiter.api.Test;
77

8+
import java.util.ArrayList;
9+
import java.util.Iterator;
10+
import java.util.List;
11+
812
import static org.junit.jupiter.api.Assertions.*;
913

1014
class OptionTest {
@@ -140,4 +144,48 @@ void inspectErr() {
140144
assertEquals(getSome(), getSome().inspectErr(mRunnable));
141145
mRunnable.assertNotCalled();
142146
}
147+
148+
@Test
149+
void stream() {
150+
assertEquals(List.of(314), getSome().stream().toList());
151+
assertEquals(List.of(), getNone().stream().toList());
152+
}
153+
154+
@Test
155+
void iterator() {
156+
{
157+
Iterator<Integer> oks = getSome().iterator();
158+
assertTrue(oks.hasNext());
159+
assertEquals(314, oks.next());
160+
assertFalse(oks.hasNext());
161+
}
162+
{
163+
List<Integer> ls = new ArrayList<>();
164+
getSome().iterator().forEachRemaining(ls::add);
165+
assertEquals(List.of(314), ls);
166+
}
167+
{
168+
Iterator<Integer> oks = getNone().iterator();
169+
assertFalse(oks.hasNext());
170+
}
171+
{
172+
List<Integer> ls = new ArrayList<>();
173+
getNone().iterator().forEachRemaining(ls::add);
174+
assertEquals(List.of(), ls);
175+
}
176+
}
177+
178+
@Test
179+
void forEach() {
180+
MockedConsumer<Integer> intCons = new MockedConsumer<>();
181+
{
182+
getSome().forEach(intCons);
183+
intCons.assertCalledOnceWith(314);
184+
}
185+
intCons.reset();
186+
{
187+
getNone().forEach(intCons);
188+
intCons.assertNotCalled();
189+
}
190+
}
143191
}

0 commit comments

Comments
 (0)