All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.shapesecurity.functional.data.Maybe Maven / Gradle / Ivy

There is a newer version: 3.1.0
Show newest version
/*
 * Copyright 2014 Shape Security, Inc.
 *
 * 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.shapesecurity.functional.data;

import com.shapesecurity.functional.Effect;
import com.shapesecurity.functional.F;
import com.shapesecurity.functional.Thunk;
import com.shapesecurity.functional.Unit;


import java.util.Optional;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public abstract class Maybe {
    private final static Maybe NOTHING = new Nothing<>();

    // class local
    private Maybe() {
    }

    @SuppressWarnings("unchecked")
    @NotNull
    public static  Maybe nothing() {
        return (Maybe) NOTHING;
    }

    @NotNull
    public static  Maybe just(@NotNull A a) {
        return new Just<>(a);
    }

    @NotNull
    public static  Maybe fromNullable(@Nullable A a) {
        if (a == null) {
            return nothing();
        }
        return just(a);
    }

    @Nullable
    public abstract A toNullable();

    public static  Maybe join(@NotNull Maybe> m) {
        return m.flatMap((a) -> a);
    }

    @NotNull
    public static  ImmutableList catMaybes(@NotNull ImmutableList> l) {
        return l.foldRight((a, b) -> a.maybe(b, c -> ImmutableList.cons(c, b)), ImmutableList.nil());
    }

    @NotNull
    public static  ImmutableList mapMaybe(@NotNull final F f, @NotNull ImmutableList> l) {
        return l.foldRight((a, b) -> a.maybe(b, v -> ImmutableList.cons(f.apply(v), b)), ImmutableList.nil());
    }

    @SuppressWarnings("BooleanParameter")
    @NotNull
    public static  Maybe iff(boolean test, @NotNull A a) {
        if (test) {
            return just(a);
        }
        return nothing();
    }

    public abstract boolean eq(@NotNull Maybe maybe);

    @SuppressWarnings("unchecked")
    @Override
    public final boolean equals(Object obj) {
        return obj == this || obj instanceof Maybe && this.eq((Maybe) obj);
    }

    @Override
    public abstract int hashCode();

    @NotNull
    public abstract A just() throws NullPointerException;

    @NotNull
    public abstract  B maybe(@NotNull B def, @NotNull F f);

    public final void foreach(@NotNull Effect f) {
        map(f);
    }

    public abstract boolean isJust();

    public final boolean isNothing() {
        return !this.isJust();
    }

    @NotNull
    public abstract ImmutableList toList();

    @NotNull
    public abstract A orJust(@NotNull A a);

    @NotNull
    public abstract A orJustLazy(@NotNull Thunk a);

    @NotNull
    public abstract  Maybe map(@NotNull F f);

    @NotNull
    public final  Maybe bind(@NotNull F> f) {
        return this.flatMap(f);
    }

    @NotNull
    public abstract  Maybe flatMap(@NotNull F> f);

    @NotNull
    public abstract Maybe filter(@NotNull F f);

    private static class Just extends Maybe {
        @NotNull
        private final A value;
        private Thunk hashCodeThunk = Thunk.from(this::calcHashCode);

        private Just(@NotNull A value) {
            super();
            this.value = value;
        }

        private int calcHashCode() {
            return HashCodeBuilder.put(this.value.hashCode(), "Just");
        }

        @Nullable
        @Override
        public A toNullable() {
            return value;
        }

        @Override
        public boolean eq(@NotNull Maybe maybe) {
            return maybe instanceof Just && maybe.just().equals(this.value);
        }

        @Override
        public int hashCode() {
            return this.hashCodeThunk.get();
        }

        @NotNull
        @Override
        public A just() throws NullPointerException {
            return this.value;
        }

        @NotNull
        @Override
        public  B maybe(@NotNull B def, @NotNull F f) {
            return f.apply(this.value);
        }

        @Override
        public boolean isJust() {
            return true;
        }

        @NotNull
        @Override
        public ImmutableList toList() {
            return ImmutableList.cons(this.value, ImmutableList.nil());
        }

        @NotNull
        @Override
        public A orJust(@NotNull A a) {
            return this.value;
        }

        @NotNull
        @Override
        public A orJustLazy(@NotNull Thunk a) {
            return this.value;
        }

        @NotNull
        @Override
        public  Maybe map(@NotNull F f) {
            return Maybe.just(f.apply(this.value));
        }

        @NotNull
        @Override
        public  Maybe flatMap(@NotNull F> f) {
            return f.apply(this.value);
        }

        @NotNull
        @Override
        public Maybe filter(@NotNull F f) {
            return f.apply(this.value) ? this : Maybe.nothing();
        }
    }

    private static class Nothing extends Maybe {
        private final static int HASH_CODE = HashCodeBuilder.put(HashCodeBuilder.init(), "Nothing");

        @Nullable
        @Override
        public A toNullable() {
            return null;
        }

        @Override
        public boolean eq(@NotNull Maybe maybe) {
            return maybe == this;
        }

        @Override
        public final int hashCode() {
            return HASH_CODE;
        }

        @NotNull
        @Override
        public A just() throws NullPointerException {
            throw new NullPointerException("Maybe.just failed");
        }

        @NotNull
        @Override
        public  B maybe(@NotNull B def, @NotNull F f) {
            return def;
        }

        @Override
        public boolean isJust() {
            return false;
        }

        @NotNull
        @Override
        public ImmutableList toList() {
            return ImmutableList.nil();
        }

        @NotNull
        @Override
        public A orJust(@NotNull A a) {
            return a;
        }

        @NotNull
        @Override
        public A orJustLazy(@NotNull Thunk a) {
            return a.get();
        }

        @SuppressWarnings("unchecked")
        @NotNull
        @Override
        public  Maybe map(@NotNull F f) {
            return (Maybe) NOTHING;
        }

        @SuppressWarnings("unchecked")
        @NotNull
        @Override
        public  Maybe flatMap(@NotNull F> f) {
            return (Maybe) NOTHING;
        }

        @NotNull
        @Override
        public Maybe filter(@NotNull F f) {
            return this;
        }
    }
}