001/*
002 * This file is part of OCaml-Java runtime.
003 * Copyright (C) 2007-2013 Xavier Clerc.
004 *
005 * OCaml-Java runtime is free software; you can redistribute it and/or modify
006 * it under the terms of the GNU Lesser General Public License as published by
007 * the Free Software Foundation; either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * OCaml-Java runtime is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.ocamljava.runtime.wrappers;
020
021import org.ocamljava.runtime.values.Value;
022
023/**
024 * The {@code OCamlOption} class is the wrapper class for OCaml values of
025 * type {@code 'a option}.
026 *
027 * @author <a href="mailto:xclerc@ocamljava.org">Xavier Clerc</a>
028 * @version 2.0
029 * @since 2.0
030 */
031public final class OCamlOption<T extends OCamlValue> extends OCamlValue {
032
033    /** Wrapper for nested value. */
034    private final Wrapper<T> wrapper;
035
036    /**
037     * Constructs a new instance wrapping the passed value.
038     * @param w wrapper for nested value - may be {@code null} for {@code None} values
039     * @param v value to wrap - should not be {@code null}
040     */
041    private OCamlOption(final Wrapper<T> w, final Value v) {
042        super(v);
043        assert w != null : "null w";
044        this.wrapper = w;
045    } // end constructor(Wrapper<T>, Value)
046
047    /**
048     * {@inheritDoc}
049     */
050    @Override
051    public Wrapper<? extends OCamlOption<T>> getWrapper() {
052        return OCamlOption.wrapper(this.wrapper);
053    } // end method 'getWrapper()'
054
055    /**
056     * {@inheritDoc}
057     */
058    @Override
059    public Wrapper<? extends OCamlValue> getWrapper(final int idx) {
060        switch (idx) {
061        case 0: return this.wrapper;
062        default: return OCamlUnit.WRAPPER;
063        } // end switch
064    } // end method 'getWrapper(int)'
065
066    /**
067     * Returns the wrapped value.
068     * @return the wrapped value if some, or {@code null} if none
069     */
070    public T get() {
071        if (this.value.isLong()) {
072            return null;
073        } else {
074            return this.wrapper.wrap(this.value.get0());
075        } // end if/else
076    } // end method 'get()'
077
078    /**
079     * {@inheritDoc}
080     */
081    @Override
082    public int hashCode() {
083        return this.value.hashCode();
084    } // end method 'hashCode()'
085
086    /**
087     * {@inheritDoc}
088     */
089    @Override
090    public boolean equals(final Object obj) {
091        if (obj instanceof OCamlOption) {
092            final OCamlOption<?> that = (OCamlOption) obj;
093            if (this.value.isLong()) {
094                if (that.value.isLong()) {
095                    return this.value.asLong() == that.value.asLong();
096                } else {
097                    return false;
098                } // end if/else
099            } else {
100                if (that.value.isLong()) {
101                    return false;
102                } else {
103                    return this.value.get0() == that.value.get0();
104                } // end if/else
105            } // end if/else
106        } else {
107            return false;
108        } // end if/else
109    } // end method 'equals(Object)'
110
111    /**
112     * {@inheritDoc}
113     */
114    @Override
115    public String toString() {
116        final StringBuilder sb = new StringBuilder();
117        sb.append("OCamlOption(");
118        if (this.value.isLong()) {
119            sb.append("None");
120        } else {
121            sb.append("Some(");
122            sb.append(this.wrapper.wrap(this.value.get0()).toString());
123            sb.append(")");
124        } // end if/else
125        sb.append(")");
126        return sb.toString();
127    } // end method 'toString()'
128
129    /**
130     * Constructs a new {@code 'a option} value, and wraps it.
131     * @param v value to wrap
132     * @return a new {@code OCamlOption} instance wrapping the passed value
133     *         as {@code Some v}
134     */
135    @SuppressWarnings("unchecked")
136    public static <T extends OCamlValue> OCamlOption<T> create(final T v) {
137        return new OCamlOption<T>((Wrapper<T>) v.getWrapper(),
138                                  Value.createBlock(0, v.value()));
139    } // end method 'create(T)'
140
141    /**
142     * Constructs a new {@code 'a option} value, and wraps it.
143     * @return a new {@code OCamlOption} instance wrapping the passed value
144     *         as {@code None}
145     */
146    @SuppressWarnings("unchecked")
147    public static <T extends OCamlValue> OCamlOption<T> create() {
148        return new OCamlOption<T>((Wrapper<T>) OCamlUnit.WRAPPER, Value.ZERO);
149    } // end method 'create(T)'
150
151    /**
152     * Wraps the passed value.
153     * @param w wrapper for nested value - should not be {@code null}
154     * @param v value to wrap - should not be {@code null}
155     * @return a new {@code OCamlOption} instance wrapping the passed value
156     */
157    public static <T extends OCamlValue> OCamlOption<T> wrap(final Wrapper<T> w,
158                                                             final Value v) {
159        assert v != null : "null v";
160        return new OCamlOption<T>(w, v);
161    } // end method 'wrap(Wrapper<T>, Value)'
162
163    /**
164     * Returns a wrapper for {@code OCamlOption} values.
165     * @param w wrapper for nested value - should not be {@code null}
166     * @return a wrapper for {@code OCamlOption} values
167     */
168    @SuppressWarnings("unchecked")
169    public static <T extends OCamlValue> Wrapper<? extends OCamlOption<T>> wrapper(final Wrapper<T> w) {
170        return new ComposedWrapper<OCamlOption<T>>() {
171            /**
172             * {@inheritDoc}
173             */
174            @Override
175                public OCamlOption<T> wrap(final Value v) {
176                return new OCamlOption<T>(w, v);
177            } // end method 'wrap(Value)'
178        }; // end anonymous inner-class
179    } // end method 'wrapper(Wrapper<T>)'
180
181} // end class 'OCamlOption'