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