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 OCamlFunction4} class represent an OCaml function taking four
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 OCamlFunction4<T0 extends OCamlValue,
036                                     T1 extends OCamlValue,
037                                     T2 extends OCamlValue,
038                                     T3 extends OCamlValue,
039                                     TR extends OCamlValue> extends OCamlValue {
040
041    /** Wrapper for first parameter. */
042    protected final Wrapper<T0> wrapper0;
043
044    /** Wrapper for second parameter. */
045    protected final Wrapper<T1> wrapper1;
046
047    /** Wrapper for third parameter. */
048    protected final Wrapper<T2> wrapper2;
049
050    /** Wrapper for fourth parameter. */
051    protected final Wrapper<T3> wrapper3;
052
053    /** Wrapper for return value. */
054    protected final Wrapper<TR> wrapperr;
055
056    /** Method handle for function actually called from the OCaml runtime. */
057    private static final MethodHandle METHOD_HANDLE;
058
059    static {
060        MethodHandle mh;
061        try {
062            final MethodHandles.Lookup lookup = MethodHandles.lookup();
063            final MethodType mt = MethodType.methodType(Value.class,
064                                                        Value.class,
065                                                        Value.class,
066                                                        Value.class,
067                                                        Value.class);
068            mh = lookup.findVirtual(OCamlFunction4Caller.class, "called", mt);
069        } catch (final NoSuchMethodException | IllegalAccessException e) {
070            assert false : "OCamlFunction4: unable to get method handle";
071            mh = null;
072        } // end try/catch
073        METHOD_HANDLE = mh;
074    } // end static block
075
076    /**
077     * Constructs a new instance. <br/>
078     * To be used by Java implementations.
079     * @param w0 wrapper for first parameter - should not be {@code null}
080     * @param w1 wrapper for second parameter - should not be {@code null}
081     * @param w2 wrapper for third parameter - should not be {@code null}
082     * @param w3 wrapper for fourth parameter - should not be {@code null}
083     * @param wr wrapper for result - should not be {@code null}
084     */
085    public OCamlFunction4(final Wrapper<T0> w0,
086                          final Wrapper<T1> w1,
087                          final Wrapper<T2> w2,
088                          final Wrapper<T3> w3,
089                          final Wrapper<TR> wr) {
090        super(Value.UNIT);
091        assert w0 != null : "null w0";
092        assert w1 != null : "null w1";
093        assert w2 != null : "null w2";
094        assert w3 != null : "null w3";
095        assert wr != null : "null wr";
096        this.wrapper0 = w0;
097        this.wrapper1 = w1;
098        this.wrapper2 = w2;
099        this.wrapper3 = w3;
100        this.wrapperr = wr;
101    } // end constructor(Wrapper<T0>, Wrapper<T1>, Wrapper<T2>, Wrapper<T3>, Wrapper<TR>)
102
103    /**
104     * Constructs a new instance. <br/>
105     * To be used by Java implementations.
106     */
107    @SuppressWarnings("unchecked")
108    public OCamlFunction4() {
109        this((Wrapper<T0>) OCamlValue.WRAPPER,
110             (Wrapper<T1>) OCamlValue.WRAPPER,
111             (Wrapper<T2>) OCamlValue.WRAPPER,
112             (Wrapper<T3>) OCamlValue.WRAPPER,
113             (Wrapper<TR>) OCamlValue.WRAPPER);
114    } // end empty constructor
115
116    /**
117     * Constructs a new instance from a value. <br/>
118     * To be used by OCaml implementations.
119     * @param w0 wrapper for first parameter - should not be {@code null}
120     * @param w1 wrapper for second parameter - should not be {@code null}
121     * @param w2 wrapper for third parameter - should not be {@code null}
122     * @param w3 wrapper for fourth parameter - should not be {@code null}
123     * @param wr wrapper for result - should not be {@code null}
124     */
125    OCamlFunction4(final Value v,
126                   final Wrapper<T0> w0,
127                   final Wrapper<T1> w1,
128                   final Wrapper<T2> w2,
129                   final Wrapper<T3> w3,
130                   final Wrapper<TR> wr) {
131        super(v);
132        assert w0 != null : "null w0";
133        assert w1 != null : "null w1";
134        assert w2 != null : "null w2";
135        assert w3 != null : "null w3";
136        assert wr != null : "null wr";
137        this.wrapper0 = w0;
138        this.wrapper1 = w1;
139        this.wrapper2 = w2;
140        this.wrapper3 = w3;
141        this.wrapperr = wr;
142    } // end constructor(Value, Wrapper<T0>, Wrapper<T1>, Wrapper<T2>, Wrapper<T3>, Wrapper<TR>)
143
144    /**
145     * {@inheritDoc}
146     */
147    @Override
148    public final Wrapper<? extends OCamlFunction4<T0, T1, T2, T3, TR>> getWrapper() {
149        return OCamlFunction4.wrapper(this.wrapper0,
150                                      this.wrapper1,
151                                      this.wrapper2,
152                                      this.wrapper3,
153                                      this.wrapperr);
154    } // end method 'getWrapper()'
155
156    /**
157     * {@inheritDoc}
158     */
159    @Override
160    public Wrapper<? extends OCamlValue> getWrapper(final int idx) {
161        switch (idx) {
162        case 0: return this.wrapper0;
163        case 1: return this.wrapper1;
164        case 2: return this.wrapper2;
165        case 3: return this.wrapper3;
166        case 4: return this.wrapperr;
167        default: return OCamlUnit.WRAPPER;
168        } // end switch
169    } // end method 'getWrapper(int)'
170
171    /**
172     * Returns the closure to be executed from the OCaml runtime.
173     * @param w0 wrapper for first parameter - should not be {@code null}
174     * @param w1 wrapper for second parameter - should not be {@code null}
175     * @param w2 wrapper for third parameter - should not be {@code null}
176     * @param w3 wrapper for fourth parameter - should not be {@code null}
177     * @return the closure to be executed on the OCaml side
178     */
179    public Value getClosure(final Wrapper<T0> w0,
180                            final Wrapper<T1> w1,
181                            final Wrapper<T2> w2,
182                            final Wrapper<T3> w3) {
183        assert w0 != null : "null w0";
184        assert w1 != null : "null w1";
185        assert w2 != null : "null w2";
186        assert w3 != null : "null w3";
187        final OCamlFunction4Caller<T0, T1, T2, T3, TR> ofc = new OCamlFunction4Caller<>(w0, w1, w2, w3, this);
188        return Value.createClosure(OCamlFunction4.METHOD_HANDLE.bindTo(ofc), 4);
189    } // end method 'getClosure(Wrapper<T0>, Wrapper<T1>, Wrapper<T2>, Wrapper<T3>)'
190
191    /**
192     * The actual implementation of the function
193     * @param p0 first parameter - should not be {@code null}
194     * @param p1 second parameter - should not be {@code null}
195     * @param p2 third parameter - should not be {@code null}
196     * @param p3 fourth parameter - should not be {@code null}
197     * @throws OCamlException if function fails
198     */
199    public abstract TR execute(final T0 p0,
200                               final T1 p1,
201                               final T2 p2,
202                               final T3 p3)
203        throws OCamlException;
204
205    /**
206     * {@inheritDoc}
207     */
208    @Override
209    public final int hashCode() {
210        return super.hashCode();
211    } // end method 'hashCode()'
212
213    /**
214     * {@inheritDoc}
215     */
216    @Override
217    public final boolean equals(final Object obj) {
218        if (obj instanceof OCamlFunction4) {
219            final OCamlFunction4<?, ?, ?, ?, ?> that = (OCamlFunction4) obj;
220            return this == that;
221        } else {
222            return false;
223        } // end if/else
224    } // end method 'equals(Object)'
225
226    /**
227     * {@inheritDoc}
228     */
229    @Override
230    public final String toString() {
231        return "OCamlFunction4(...)";
232    } // end method 'toString()'
233
234    /**
235     * Wraps the passed value.
236     * @param w0 wrapper for first parameter - should not be {@code null}
237     * @param w1 wrapper for second parameter - should not be {@code null}
238     * @param w2 wrapper for third parameter - should not be {@code null}
239     * @param w3 wrapper for fourth parameter - should not be {@code null}
240     * @param wr wrapper for result - should not be {@code null}
241     * @param v value to wrap - should not be {@code null}
242     * @return a new {@code OCamlFunction4} instance wrapping the passed value
243     */
244    public static <T0 extends OCamlValue,
245                   T1 extends OCamlValue,
246                   T2 extends OCamlValue,
247                   T3 extends OCamlValue,
248                   TR extends OCamlValue>
249        OCamlFunction4<T0, T1, T2, T3, TR> wrap(final Wrapper<T0> w0,
250                                                final Wrapper<T1> w1,
251                                                final Wrapper<T2> w2,
252                                                final Wrapper<T3> w3,
253                                                final Wrapper<TR> wr,
254                                                final Value v) {
255        assert w0 != null : "null w0";
256        assert w1 != null : "null w1";
257        assert w2 != null : "null w2";
258        assert w3 != null : "null w3";
259        assert wr != null : "null wr";
260        assert v != null : "null v";
261        return new OCamlFunction4Impl<T0, T1, T2, T3, TR>(w0, w1, w2, w3, wr, v);
262    } // end method 'wrap(Wrapper<T0>, Wrapper<T1>, Wrapper<T2>, Wrapper<T3>, Wrapper<TR>, Value)'
263
264    /**
265     * Returns a wrapper for {@code OCamlFunction4} values.
266     * @param w0 wrapper for first parameter - should not be {@code null}
267     * @param w1 wrapper for second parameter - should not be {@code null}
268     * @param w2 wrapper for third parameter - should not be {@code null}
269     * @param w3 wrapper for fourth parameter - should not be {@code null}
270     * @param wr wrapper for result - should not be {@code null}
271     * @return a wrapper for {@code OCamlFunction4} values
272     */
273    @SuppressWarnings("unchecked")
274    public static <T0 extends OCamlValue,
275                   T1 extends OCamlValue,
276                   T2 extends OCamlValue,
277                   T3 extends OCamlValue,
278                   TR extends OCamlValue>
279        Wrapper<? extends OCamlFunction4<T0, T1, T2, T3, TR>> wrapper(final Wrapper<T0> w0,
280                                                                      final Wrapper<T1> w1,
281                                                                      final Wrapper<T2> w2,
282                                                                      final Wrapper<T3> w3,
283                                                                      final Wrapper<TR> wr) {
284        assert w0 != null : "null w0";
285        assert w1 != null : "null w1";
286        assert w2 != null : "null w2";
287        assert w3 != null : "null w3";
288        assert wr != null : "null wr";
289        return new ComposedWrapper<OCamlFunction4<T0, T1, T2, T3, TR>>(w0, w1, w2, w3, wr) {
290            /**
291             * {@inheritDoc}
292             */
293            @Override
294                public OCamlFunction4<T0, T1, T2, T3, TR> wrap(final Value v) {
295                return new OCamlFunction4Impl<T0, T1, T2, T3, TR>(w0, w1, w2, w3, wr, v);
296            } // end method 'wrap(Value)'
297        }; // end anonymous inner-class
298    } // end method 'wrapper(Wrapper<T0>, Wrapper<T1>, Wrapper<T2>, Wrapper<T3>, Wrapper<TR>)'
299
300} // end class 'OCamlFunction4'