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 * 'b}.
026 *
027 * @author <a href="mailto:xclerc@ocamljava.org">Xavier Clerc</a>
028 * @version 2.0
029 * @since 2.0
030 */
031public final class OCamlTuple2<T0 extends OCamlValue,
032                               T1 extends OCamlValue> extends OCamlValue {
033
034    /** Wrapper for nested value. */
035    private final Wrapper<T0> wrapper0;
036
037    /** Wrapper for nested value. */
038    private final Wrapper<T1> wrapper1;
039
040    /**
041     * Constructs a new instance wrapping the passed value.
042     * @param w0 wrapper for nested value - should not be {@code null}
043     * @param w1 wrapper for nested value - should not be {@code null}
044     * @param v value to wrap - should not be {@code null}
045     */
046    private OCamlTuple2(final Wrapper<T0> w0,
047                        final Wrapper<T1> w1,
048                        final Value v) {
049        super(v);
050        assert w0 != null : "null w0";
051        assert w1 != null : "null w1";
052        this.wrapper0 = w0;
053        this.wrapper1 = w1;
054    } // end constructor(Wrapper<T0>, Wrapper<T1>, Value)
055
056    /**
057     * {@inheritDoc}
058     */
059    @Override
060    public Wrapper<? extends OCamlTuple2<T0, T1>> getWrapper() {
061        return OCamlTuple2.wrapper(this.wrapper0,
062                                   this.wrapper1);
063    } // end method 'getWrapper()'
064
065    /**
066     * {@inheritDoc}
067     */
068    @Override
069    public Wrapper<? extends OCamlValue> getWrapper(final int idx) {
070        switch (idx) {
071        case 0: return this.wrapper0;
072        case 1: return this.wrapper1;
073        default: return OCamlUnit.WRAPPER;
074        } // end switch
075    } // end method 'getWrapper(int)'
076
077    /**
078     * Returns the first element of the wrapped value.
079     * @return the first element of the wrapped value
080     */
081    public T0 get0() {
082        return this.wrapper0.wrap(this.value.get0());
083    } // end method 'get0()'
084
085    /**
086     * Returns the second element of the wrapped value.
087     * @return the second element of the wrapped value
088     */
089    public T1 get1() {
090        return this.wrapper1.wrap(this.value.get1());
091    } // end method 'get1()'
092
093    /**
094     * {@inheritDoc}
095     */
096    @Override
097    public int hashCode() {
098        return this.value.get0().hashCode()
099            + this.value.get1().hashCode();
100    } // end method 'hashCode()'
101
102    /**
103     * {@inheritDoc}
104     */
105    @Override
106    public boolean equals(final Object obj) {
107        if (obj instanceof OCamlTuple2) {
108            final OCamlTuple2<?, ?> that = (OCamlTuple2) obj;
109            return this.value.get0().equals(that.value.get0())
110                && this.value.get1().equals(that.value.get1());
111        } else {
112            return false;
113        } // end if/else
114    } // end method 'equals(Object)'
115
116    /**
117     * {@inheritDoc}
118     */
119    @Override
120    public String toString() {
121        final StringBuilder sb = new StringBuilder();
122        sb.append("OCamlTuple2(");
123        sb.append(this.wrapper0.wrap(this.value.get0()).toString());
124        sb.append(", ");
125        sb.append(this.wrapper1.wrap(this.value.get1()).toString());
126        sb.append(")");
127        return sb.toString();
128    } // end method 'toString()'
129
130    /**
131     * Constructs a new {@code 'a * 'b} value, and wraps it.
132     * @param v0 first element of value to wrap - should not be {@code null}
133     * @param v1 second element of value to wrap - should not be {@code null}
134     * @return a new {@code OCamlTuple2} instance wrapping the passed values
135     */
136    @SuppressWarnings("unchecked")
137    public static <T0 extends OCamlValue,
138                   T1 extends OCamlValue>
139        OCamlTuple2<T0, T1> create(final T0 v0,
140                                   final T1 v1) {
141        assert v0 != null : "null v0";
142        assert v1 != null : "null v1";
143        return new OCamlTuple2<T0, T1>((Wrapper<T0>) v0.getWrapper(),
144                                       (Wrapper<T1>) v1.getWrapper(),
145                                       Value.createBlock(0,
146                                                         v0.value(),
147                                                         v1.value()));
148    } // end method 'create(T0, T1)'
149
150    /**
151     * Wraps the passed value.
152     * @param w0 wrapper for nested value - should not be {@code null}
153     * @param w1 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 OCamlTuple2} instance wrapping the passed value
156     */
157    public static <T0 extends OCamlValue,
158                   T1 extends OCamlValue>
159        OCamlTuple2<T0, T1> wrap(final Wrapper<T0> w0,
160                                 final Wrapper<T1> w1,
161                                 final Value v) {
162        assert w0 != null : "null w0";
163        assert w1 != null : "null w1";
164        assert v != null : "null v";
165        return new OCamlTuple2<T0, T1>(w0, w1, v);
166    } // end method 'wrap(Wrapper<T0>, Wrapper<T1>, Value)'
167
168    /**
169     * Returns a wrapper for {@code OCamlOption} values.
170     * @param w0 wrapper for nested value - should not be {@code null}
171     * @param w1 wrapper for nested value - should not be {@code null}
172     * @return a wrapper for {@code OCamlOption} values
173     */
174    @SuppressWarnings("unchecked")
175    public static <T0 extends OCamlValue,
176                   T1 extends OCamlValue>
177        Wrapper<? extends OCamlTuple2<T0, T1>> wrapper(final Wrapper<T0> w0,
178                                                       final Wrapper<T1> w1) {
179        return new ComposedWrapper<OCamlTuple2<T0, T1>>(w0, w1) {
180            /**
181             * {@inheritDoc}
182             */
183            @Override
184                public OCamlTuple2<T0, T1> wrap(final Value v) {
185                return new OCamlTuple2<T0, T1>(w0, w1, v);
186            } // end method 'wrap(Value)'
187        }; // end anonymous inner-class
188    } // end method 'wrapper(Wrapper<T0>, Wrapper<T1>)'
189
190} // end class 'OCamlTuple2'