com.softwaremill.jox.CollectSource Maven / Gradle / Ivy
package com.softwaremill.jox;
import java.util.function.Function;
public class CollectSource implements Source {
private final Source original;
private final Function f;
/**
* A view on the {@code original} source, which transforms the received values using the provided function {@code f}.
* If {@code f} returns {@code null}, the value will be skipped, and another value will be received.
*
* The same logic applies to receive clauses created using this source, which can be used in {@link Select#select(SelectClause[])}.
*
* @param original The original source, from which values are received.
* @param f The mapping / filtering function. If the function returns {@code null}, the value will be skipped.
*/
public CollectSource(Source original, Function f) {
this.original = original;
this.f = f;
}
@Override
public T receive() throws InterruptedException {
while (true) {
var r = original.receive();
var t = f.apply(r);
// a null indicates that the value should not be collected (skipped)
if (t != null) {
return t;
}
}
}
@Override
public Object receiveOrClosed() throws InterruptedException {
while (true) {
var r = original.receiveOrClosed();
if (r instanceof ChannelClosed c) {
return c;
} else {
//noinspection unchecked
var t = f.apply((V) r);
// a null indicates that the value should not be collected (skipped)
if (t != null) {
return t;
}
}
}
}
@Override
public SelectClause receiveClause() {
return original.receiveClause(v -> {
var t = f.apply(v);
if (t != null) {
return t;
} else {
// `null` is a valid return value from a select clause (default for send clauses and allowed for callbacks)
// that's why we need a marker to indicate that the value should not be collected, when the result of `f`
// is `null`. This is then handled in `Select`.
//noinspection unchecked
return (T) RestartSelectMarker.RESTART;
}
});
}
@Override
public SelectClause receiveClause(Function callback) {
return original.receiveClause(v -> {
var t = f.apply(v);
if (t != null) {
return callback.apply(t);
} else {
//noinspection unchecked
return (U) RestartSelectMarker.RESTART;
}
});
}
// delegates for closeable channel
@Override
public void done() {
original.done();
}
@Override
public Object doneOrClosed() {
return original.doneOrClosed();
}
@Override
public void error(Throwable reason) {
original.error(reason);
}
@Override
public Object errorOrClosed(Throwable reason) {
return original.errorOrClosed(reason);
}
@Override
public ChannelClosed closedForSend() {
return original.closedForSend();
}
@Override
public ChannelClosed closedForReceive() {
return original.closedForReceive();
}
}