/* * Quasar: lightweight threads and actors for the JVM. * Copyright (c) 2013-2014, Parallel Universe Software Co. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 3.0 * as published by the Free Software Foundation. */ package co.paralleluniverse.strands.channels; import co.paralleluniverse.common.util.Function2; import co.paralleluniverse.fibers.FiberFactory; import co.paralleluniverse.fibers.SuspendExecution; import co.paralleluniverse.strands.SuspendableAction1; import co.paralleluniverse.strands.SuspendableAction2; import com.google.common.base.Function; import com.google.common.base.Predicate; /** * A {@link ReceivePort} with additional functional-transform operations, usually wrapping a plain {@link ReceivePort}. * * @author pron */ public class TransformingReceivePort<T> extends DelegatingReceivePort<T> { TransformingReceivePort(ReceivePort<T> target) { super(target); } /** * Returns a {@link TransformingReceivePort} that filters messages that satisfy a predicate from this given channel. * All messages (even those not satisfying the predicate) will be consumed from the original channel; those that don't satisfy the predicate will be silently discarded. * <p/> * The returned {@code TransformingReceivePort} has the same {@link Object#hashCode() hashCode} as {@code channel} and is {@link Object#equals(Object) equal} to it. * * @param pred the filtering predicate * @return A {@link TransformingReceivePort} that will receive all those messages from the original channel which satisfy the predicate (i.e. the predicate returns {@code true}). */ public TransformingReceivePort<T> filter(Predicate<T> pred) { return Channels.transform(Channels.filter(this, pred)); } /** * Returns a {@link TransformingReceivePort} that receives messages that are transformed by a given mapping function from this channel. * <p> * The returned {@code TransformingReceivePort} has the same {@link Object#hashCode() hashCode} as {@code channel} and is {@link Object#equals(Object) equal} to it. * * @param f the mapping function * @return a {@link TransformingReceivePort} that returns messages that are the result of applying the mapping function to the messages received on the given channel. */ public <U> TransformingReceivePort<U> map(Function<T, U> f) { return Channels.transform(Channels.map(this, f)); } /** * Returns a {@link TransformingReceivePort} from which receiving messages that are transformed from a given channel by a given reduction function. * <p/> * The returned {@code TransformingReceivePort} has the same {@link Object#hashCode() hashCode} as {@code channel} and is {@link Object#equals(Object) equal} to it. * * @param f The reduction function. * @param init The initial input to the reduction function. * @return a {@link ReceivePort} that returns messages that are the result of applying the reduction function to the messages received on the given channel. */ public <U> TransformingReceivePort<U> reduce(Function2<U, T, U> f, U init) { return Channels.transform(Channels.reduce(this, f, init)); } /** * Returns a {@link TransformingReceivePort} that maps exceptions thrown by the underlying channel * (by channel transformations, or as a result of {@link SendPort#close(Throwable)} ) * into messages. * <p> * The returned {@code TransformingReceivePort} has the same {@link Object#hashCode() hashCode} as {@code channel} and is {@link Object#equals(Object) equal} to it. * * @param f the exception mapping function */ TransformingReceivePort<T> mapErrors(Function<Exception, T> f) { return Channels.transform(Channels.mapErrors(this, f)); } /** * Returns a {@link TransformingReceivePort} that receives messages that are transformed by a given flat-mapping function from this channel. * Unlike {@link #map(Function) map}, the mapping function does not returns a single output message for every input message, but * a new {@code ReceivePort}. All the returned ports are concatenated into a single {@code ReceivePort} that receives the messages received by all * the ports in order. * <p> * To return a single value the mapping function can make use of {@link Channels#singletonReceivePort(Object)}. To return a collection, * it can make use of {@link Channels#toReceivePort(Iterable)}. To emit no values, the function can return {@link Channels#emptyReceivePort()} * or {@code null}. * <p> * The returned {@code TransformingReceivePort} can only be safely used by a single receiver strand. * <p> * The returned {@code TransformingReceivePort} has the same {@link Object#hashCode() hashCode} as {@code channel} and is {@link Object#equals(Object) equal} to it. * * @param f the mapping function * @return a {@link TransformingReceivePort} that returns messages that are the result of applying the mapping function to the messages received on the given channel. */ public <U> TransformingReceivePort<U> flatMap(Function<T, ReceivePort<U>> f) { return Channels.transform(Channels.flatMap(this, f)); } /** * Returns a {@link TakeReceivePort} that can provide at most {@code count} messages from the underlying channel. * <p> * The returned {@code TransformingReceivePort} has the same {@link Object#hashCode() hashCode} as {@code channel} and is {@link Object#equals(Object) equal} to it. * * @param count The maximum number of messages extracted from the underlying channel. */ public TransformingReceivePort<T> take(final long count) { return Channels.transform(Channels.take(this, count)); } /** * Spawns a fiber that transforms values read from this channel and writes values to the {@code out} channel. * <p> * When the transformation terminates. the output channel is automatically closed. If the transformation terminates abnormally * (throws an exception), the output channel is {@link SendPort#close(Throwable) closed with that exception}. * * @param out the output channel * @param transformer the transforming operation * * @return A {@link TransformingReceivePort} wrapping the {@code out} channel. */ public <U> TransformingReceivePort<U> fiberTransform(SuspendableAction2<? extends ReceivePort<? super T>, ? extends SendPort<? extends U>> transformer, Channel<U> out) { Channels.fiberTransform(this, out, transformer); return Channels.transform(out); } /** * Spawns a fiber that transforms values read from this channel and writes values to the {@code out} channel. * <p> * When the transformation terminates. the output channel is automatically closed. If the transformation terminates abnormally * (throws an exception), the output channel is {@link SendPort#close(Throwable) closed with that exception}. * * @param fiberFactory will be used to create the fiber * @param out the output channel * @param transformer the transforming operation * * @return A {@link TransformingReceivePort} wrapping the {@code out} channel. */ public <U> TransformingReceivePort<U> fiberTransform(FiberFactory fiberFactory, SuspendableAction2<? extends ReceivePort<? super T>, ? extends SendPort<? extends U>> transformer, Channel<U> out) { Channels.fiberTransform(fiberFactory, this, out, transformer); return Channels.transform(out); } /** * Performs the given action on each message received by this channel. * This method returns only after all messages have been consumed and the channel has been closed. * * @param action */ public void forEach(SuspendableAction1<T> action) throws SuspendExecution, InterruptedException { Channels.forEach(this, action); } }