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