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.context.CodeState;
026import org.ocamljava.runtime.context.CurrentContext;
027import org.ocamljava.runtime.values.Value;
028
029/**
030 * The {@code OCamlWrappers} provides utility methods related to wrappers.
031 *
032 * @author <a href="mailto:xclerc@ocamljava.org">Xavier Clerc</a>
033 * @version 2.0
034 * @since 2.0
035 */
036public final class OCamlWrappers {
037
038    /** Identifier for callback holding object id. */
039    private static final String OID_CALLBACK = "CamlinternalOO.last_id";
040
041    /**
042     * No instance of this class.
043     */
044    private OCamlWrappers() {
045    } // end empty constructor
046
047    /**
048     * Converts a value into a {@code boolean}.
049     * @param v value to convert - should not be {@code null}
050     * @return the passed value, as a {@code boolean}
051     */
052    public static boolean asBool(final Value v) {
053        assert v != null : "null v";
054        return v != Value.FALSE;
055    } // end method 'asBool(Value)'
056
057    /**
058     * Returns a value representing a boolean.
059     * @param b boolean value to represent
060     * @return a value representing the passed boolean
061     */
062    public static Value createBool(final boolean b) {
063        return b ? Value.TRUE : Value.FALSE;
064    } // end method 'createBool(boolean)'
065
066    public static Value getAndIncrementOid() {
067        final CodeState cs = CurrentContext.getCodeState();
068        Value oid = cs.getCallback(OCamlWrappers.OID_CALLBACK);
069        if (oid == null) {
070            oid = Value.createBlock(0, Value.ZERO);
071            cs.registerCallback(OCamlWrappers.OID_CALLBACK, oid);
072        } // end if
073        final Value old = oid.get0();
074        oid.set0(Value.createLong(old.asLong() + 1));
075        return old;
076    } // end method 'getAndIncrementOid()'
077
078    /**
079     * Constructs and return a new closure for a Java virtual method.
080     * @param clazz method class - should not be {@code null}
081     * @param method method name - should not be {@code null}
082     * @param thiz target instance - should not be {@code null}
083     * @param arity method arity
084     */
085    public static Value createClosure(final Class<?> clazz,
086                                      final String method,
087                                      final Object thiz,
088                                      final int arity) {
089        assert clazz != null : "null clazz";
090        assert method != null : "null method";
091        assert thiz != null : "null thiz";
092        try {
093            final MethodHandles.Lookup lookup = MethodHandles.lookup();
094            final Class<?>[] parameters = new Class<?>[arity];
095            for (int i = 0; i < arity; i++) {
096                parameters[i] = Value.class;
097            } // end for
098            final MethodType mt = MethodType.methodType(Value.class, parameters);
099            final MethodHandle mh = lookup.findVirtual(clazz, method, mt);
100            return Value.createClosure(mh.bindTo(thiz), arity);
101        } catch (final NoSuchMethodException | IllegalAccessException e) {
102            return null;
103        } // end try/catch
104    } // end method 'createClosure(Class<?>, String, Object, int)'
105
106} // end class 'OCamlWrappers'