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 java.lang.invoke.MethodHandle;
022import java.lang.invoke.MethodHandles;
023import java.lang.invoke.MethodType;
024
025import org.ocamljava.runtime.values.Value;
026
027/**
028 * The {@code OCamlFunction3} class represent an OCaml function taking two
029 * parameter.
030 *
031 * @author <a href="mailto:xclerc@ocamljava.org">Xavier Clerc</a>
032 * @version 2.0
033 * @since 2.0
034 */
035public abstract class OCamlFunction2<T0 extends OCamlValue,
036                                     T1 extends OCamlValue,
037                                     TR extends OCamlValue> extends OCamlValue {
038
039    /** Wrapper for first parameter. */
040    protected final Wrapper<T0> wrapper0;
041
042    /** Wrapper for second parameter. */
043    protected final Wrapper<T1> wrapper1;
044
045    /** Wrapper for return value. */
046    protected final Wrapper<TR> wrapperr;
047
048    /** Method handle for function actually called from the OCaml runtime. */
049    private static final MethodHandle METHOD_HANDLE;
050
051    static {
052        MethodHandle mh;
053        try {
054            final MethodHandles.Lookup lookup = MethodHandles.lookup();
055            final MethodType mt = MethodType.methodType(Value.class,
056                                                        Value.class,
057                                                        Value.class);
058            mh = lookup.findVirtual(OCamlFunction2Caller.class, "called", mt);
059        } catch (final NoSuchMethodException | IllegalAccessException e) {
060            assert false : "OCamlFunction2: unable to get method handle";
061            mh = null;
062        } // end try/catch
063        METHOD_HANDLE = mh;
064    } // end static block
065
066    /**
067     * Constructs a new instance. <br/>
068     * To be used by Java implementations.
069     * @param w0 wrapper for first parameter - should not be {@code null}
070     * @param w1 wrapper for second parameter - should not be {@code null}
071     * @param wr wrapper for result - should not be {@code null}
072     */
073    public OCamlFunction2(final Wrapper<T0> w0,
074                          final Wrapper<T1> w1,
075                          final Wrapper<TR> wr) {
076        super(Value.UNIT);
077        assert w0 != null : "null w0";
078        assert w1 != null : "null w1";
079        assert wr != null : "null wr";
080        this.wrapper0 = w0;
081        this.wrapper1 = w1;
082        this.wrapperr = wr;
083    } // end constructor(Wrapper<T0>, Wrapper<T1>, Wrapper<TR>)
084
085    /**
086     * Constructs a new instance. <br/>
087     * To be used by Java implementations.
088     */
089    @SuppressWarnings("unchecked")
090    public OCamlFunction2() {
091        this((Wrapper<T0>) OCamlValue.WRAPPER,
092             (Wrapper<T1>) OCamlValue.WRAPPER,
093             (Wrapper<TR>) OCamlValue.WRAPPER);
094    } // end empty constructor
095
096    /**
097     * Constructs a new instance from a value. <br/>
098     * To be used by OCaml implementations.
099     * @param w0 wrapper for first parameter - should not be {@code null}
100     * @param w1 wrapper for second parameter - should not be {@code null}
101     * @param wr wrapper for result - should not be {@code null}
102     */
103    OCamlFunction2(final Value v,
104                   final Wrapper<T0> w0,
105                   final Wrapper<T1> w1,
106                   final Wrapper<TR> wr) {
107        super(v);
108        assert w0 != null : "null w0";
109        assert w1 != null : "null w1";
110        assert wr != null : "null wr";
111        this.wrapper0 = w0;
112        this.wrapper1 = w1;
113        this.wrapperr = wr;
114    } // end constructor(Value, Wrapper<T0>, Wrapper<T1>, Wrapper<TR>)
115
116    /**
117     * {@inheritDoc}
118     */
119    @Override
120    public final Wrapper<? extends OCamlFunction2<T0, T1, TR>> getWrapper() {
121        return OCamlFunction2.wrapper(this.wrapper0,
122                                      this.wrapper1,
123                                      this.wrapperr);
124    } // end method 'getWrapper()'
125
126    /**
127     * {@inheritDoc}
128     */
129    @Override
130    public Wrapper<? extends OCamlValue> getWrapper(final int idx) {
131        switch (idx) {
132        case 0: return this.wrapper0;
133        case 1: return this.wrapper1;
134        case 2: return this.wrapperr;
135        default: return OCamlUnit.WRAPPER;
136        } // end switch
137    } // end method 'getWrapper(int)'
138
139    /**
140     * Returns the closure to be executed from the OCaml runtime.
141     * @param w0 wrapper for first parameter - should not be {@code null}
142     * @param w1 wrapper for second parameter - should not be {@code null}
143     * @return the closure to be executed on the OCaml side
144     */
145    public Value getClosure(final Wrapper<T0> w0,
146                            final Wrapper<T1> w1) {
147        assert w0 != null : "null w0";
148        assert w1 != null : "null w1";
149        final OCamlFunction2Caller<T0, T1, TR> ofc = new OCamlFunction2Caller<>(w0, w1, this);
150        return Value.createClosure(OCamlFunction2.METHOD_HANDLE.bindTo(ofc), 2);
151    } // end method 'getClosure(Wrapper<T0>, Wrapper<T1>)'
152
153    /**
154     * The actual implementation of the function
155     * @param p0 first parameter - should not be {@code null}
156     * @param p1 second parameter - should not be {@code null}
157     * @throws OCamlException if function fails
158     */
159    public abstract TR execute(final T0 p0,
160                               final T1 p1)
161        throws OCamlException;
162
163    /**
164     * {@inheritDoc}
165     */
166    @Override
167    public final int hashCode() {
168        return super.hashCode();
169    } // end method 'hashCode()'
170
171    /**
172     * {@inheritDoc}
173     */
174    @Override
175    public final boolean equals(final Object obj) {
176        if (obj instanceof OCamlFunction2) {
177            final OCamlFunction2<?, ?, ?> that = (OCamlFunction2) obj;
178            return this == that;
179        } else {
180            return false;
181        } // end if/else
182    } // end method 'equals(Object)'
183
184    /**
185     * {@inheritDoc}
186     */
187    @Override
188    public final String toString() {
189        return "OCamlFunction2(...)";
190    } // end method 'toString()'
191
192    /**
193     * Wraps the passed value.
194     * @param w0 wrapper for first parameter - should not be {@code null}
195     * @param w1 wrapper for second parameter - should not be {@code null}
196     * @param wr wrapper for result - should not be {@code null}
197     * @param v value to wrap - should not be {@code null}
198     * @return a new {@code OCamlFunction2} instance wrapping the passed value
199     */
200    public static <T0 extends OCamlValue,
201                   T1 extends OCamlValue,
202                   TR extends OCamlValue>
203        OCamlFunction2<T0, T1, TR> wrap(final Wrapper<T0> w0,
204                                        final Wrapper<T1> w1,
205                                        final Wrapper<TR> wr,
206                                        final Value v) {
207        assert w0 != null : "null w0";
208        assert w1 != null : "null w1";
209        assert wr != null : "null wr";
210        assert v != null : "null v";
211        return new OCamlFunction2Impl<T0, T1, TR>(w0, w1, wr, v);
212    } // end method 'wrap(Wrapper<T0>, Wrapper<T1>, Wrapper<TR>, Value)'
213
214    /**
215     * Returns a wrapper for {@code OCamlFunction2} values.
216     * @param w0 wrapper for first parameter - should not be {@code null}
217     * @param w1 wrapper for second parameter - should not be {@code null}
218     * @param wr wrapper for result - should not be {@code null}
219     * @return a wrapper for {@code OCamlFunction2} values
220     */
221    @SuppressWarnings("unchecked")
222    public static <T0 extends OCamlValue,
223                   T1 extends OCamlValue,
224                   TR extends OCamlValue>
225        Wrapper<? extends OCamlFunction2<T0, T1, TR>> wrapper(final Wrapper<T0> w0,
226                                                              final Wrapper<T1> w1,
227                                                              final Wrapper<TR> wr) {
228        assert w0 != null : "null w0";
229        assert w1 != null : "null w1";
230        assert wr != null : "null wr";
231        return new ComposedWrapper<OCamlFunction2<T0, T1, TR>>(w0, w1, wr) {
232            /**
233             * {@inheritDoc}
234             */
235            @Override
236                public OCamlFunction2<T0, T1, TR> wrap(final Value v) {
237                return new OCamlFunction2Impl<T0, T1, TR>(w0, w1, wr, v);
238            } // end method 'wrap(Value)'
239        }; // end anonymous inner-class
240    } // end method 'wrapper(Wrapper<T0>, Wrapper<T1>, Wrapper<TR>)'
241
242} // end class 'OCamlFunction2'