com.github.jeluard.guayaba.base.PartialFunctions.java Source code

Java tutorial

Introduction

Here is the source code for com.github.jeluard.guayaba.base.PartialFunctions.java

Source

/**
 * Copyright 2012 Julien Eluard
 * This project includes software developed by Julien Eluard: https://github.com/jeluard/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.jeluard.guayaba.base;

import com.google.common.base.*;
import com.google.common.collect.Iterables;
import com.google.common.reflect.TypeToken;

/**
 * Helper methods for {@link PartialFunction}.
 */
public final class PartialFunctions {

    private static final class DefinedPredicate<I, O, PF extends PartialFunction<I, O>> implements Predicate<PF> {

        private final I element;

        private DefinedPredicate(final I element) {
            this.element = element;
        }

        @Override
        public boolean apply(final PF input) {
            Preconditions.checkNotNull(input, "null input");

            return input.isDefinedAt(this.element);
        }

    }

    private static final class AssignableOutputPredicate<I, O, P extends O, PF extends PartialFunction<I, O>>
            implements Predicate<PF> {

        private final Class<P> outputType;

        private AssignableOutputPredicate(final Class<P> element) {
            this.outputType = element;
        }

        @Override
        public boolean apply(final PF input) {
            Preconditions.checkNotNull(input, "null input");

            final TypeToken<? extends PartialFunction> typeToken = TypeToken.of(input.getClass());
            final Class<?> transformedType = typeToken.resolveType(PartialFunction.class.getTypeParameters()[1])
                    .getRawType();
            return this.outputType.isAssignableFrom(transformedType);
        }

    }

    private PartialFunctions() {
    }

    /**
     * Find first {@link PartialFunction} applicable on `element`.
     *
     * @param <I>
     * @param <O>
     * @param <PF>
     * @param partialFunctions
     * @param element
     * @return result of first matching {@link PartialFunction}
     */
    public static <I, O, PF extends PartialFunction<I, ? extends O>> Optional<PF> tryFind(
            final Iterable<PF> partialFunctions, final I element) {
        Preconditions.checkNotNull(partialFunctions, "null partialFunctions");
        Preconditions.checkNotNull(element, "null element");

        return Iterables.tryFind(partialFunctions, new DefinedPredicate(element));
    }

    /**
     * Execute result of execution of first applicable {@link PartialFunction} on `element`.
     *
     * @param <I>
     * @param <O>
     * @param <PF>
     * @param partialFunctions
     * @param element
     * @return result of first matching {@link PartialFunction}
     */
    public static <I, O, PF extends PartialFunction<I, ? extends O>> Optional<? extends O> tryFindAndTransform(
            final Iterable<PF> partialFunctions, final I element) {
        Preconditions.checkNotNull(partialFunctions, "null partialFunctions");
        Preconditions.checkNotNull(element, "null element");

        return PartialFunctions.transform(PartialFunctions.tryFind(partialFunctions, element), element);
    }

    /**
     * Execute result of execution of first {@link PartialFunction} whose return type matches specified `outputType`.
     *
     * @param <I>
     * @param <O>
     * @param <P>
     * @param <PF>
     * @param partialFunctions
     * @param type
     * @param element
     * @return result of first matching {@link PartialFunction}
     */
    public static <I, O, P extends O, PF extends PartialFunction<I, ? extends O>> Optional<PF> tryFindForOutput(
            final Iterable<PF> partialFunctions, final Class<? extends P> type, final I element) {
        Preconditions.checkNotNull(partialFunctions, "null partialFunctions");
        Preconditions.checkNotNull(element, "null element");

        return Iterables.tryFind(partialFunctions,
                Predicates.and(new DefinedPredicate(element), new AssignableOutputPredicate(type)));
    }

    /**
     * @param <I>
     * @param <O>
     * @param <PF>
     * @param function
     * @param input
     * @return result of execution of optional {@link Function}
     */
    public static <I, O, PF extends PartialFunction<I, ? extends O>> Optional<? extends O> transform(
            final Optional<PF> function, final I input) {
        return Optionals.flatten(function.transform(new Function<PF, Optional<O>>() {
            @Override
            public Optional<O> apply(final PF input2) {
                return Optional.fromNullable(input2.apply(input));
            }
        }));
    }

}