1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.nicl.types;
  27 
  28 import jdk.internal.nicl.types.DescriptorParser;
  29 import jdk.internal.nicl.types.Reference;
  30 import jdk.internal.nicl.types.References;
  31 
  32 import java.nicl.layout.Address;
  33 import java.nicl.layout.Group;
  34 import java.nicl.layout.Layout;
  35 import java.nicl.layout.Sequence;
  36 
  37 import java.lang.invoke.MethodHandle;
  38 import java.nicl.metadata.NativeType;
  39 
  40 /**
  41  * This class describes the relationship between a memory layout (usually described in bits) and a Java carrier
  42  * (e.g. {@code int}, {@code long}, or any Java reference type. A {@code LayoutType} defines operation for getting/setting
  43  * the layout contents using a given Java carrier (see {@link LayoutType#getter()} and {@link LayoutType#setter()}).
  44  * Moreover, a {@code LayoutType} defines operation for creating array and pointer derived {@code LayoutType} instances
  45  * (see {@link LayoutType#array()}, {@link LayoutType#array(int)} and {@link LayoutType#pointer()}).
  46  */
  47 public class LayoutType<X> {
  48 
  49     private final Reference reference;
  50     private final Layout layout;
  51 
  52     /* package */ LayoutType(Layout layout, Reference reference) {
  53         this.reference = reference;
  54         this.layout = layout;
  55     }
  56 
  57     public long bytesSize() {
  58         return layout().bitsSize() / 8;
  59     }
  60 
  61     /**
  62      * Retrieves the memory layout associated with this {@code LayoutType}.
  63      * @return the layout.
  64      */
  65     public Layout layout() {
  66         return layout;
  67     }
  68 
  69     /**
  70      * A {@link MethodHandle} which can be used to retrieve the contents of memory layout associated
  71      * with this {@code LayoutType}. Note: the pointer passed as argument must be compatible with said layout.
  72      * <p>
  73      * A getter method handle is of the form:
  74      * {@code (Pointer) -> T}
  75      * Where {@code T} is the Java type to which the layout will be converted.
  76      * </p>
  77      * @return a 'getter' method handle.
  78      */
  79     public MethodHandle getter() {
  80         return reference.getter();
  81     }
  82 
  83     /**
  84      * A {@link MethodHandle} which can be used to store a value into the memory layout associated
  85      * with this {@code LayoutType}. Note: the pointer passed as argument must be compatible with said layout.
  86      * <p>
  87      * A setter method handle is of the form:
  88      * {@code (Pointer, T) -> V}
  89      * Where {@code T} is the Java type to which the layout will be converted.
  90      * </p>
  91      * the pointer passed as argument.
  92      * @return a 'setter' method handle.
  93      */
  94     public MethodHandle setter() {
  95         return reference.setter();
  96     }
  97 
  98     /**
  99      * Create an array {@code LayoutType} from this instance.
 100      * @return the array {@code LayoutType}.
 101      */
 102     @SuppressWarnings("unchecked")
 103     public LayoutType<Array<X>> array() {
 104         return array(0);
 105     }
 106 
 107     /**
 108      * Create an array {@code LayoutType} from this instance with given size.
 109      * @param size the array size.
 110      * @return the array {@code LayoutType}.
 111      */
 112     @SuppressWarnings("unchecked")
 113     public LayoutType<Array<X>> array(int size) {
 114         return new LayoutType<>(Sequence.of(size, layout), References.ofArray(this));
 115     }
 116 
 117     /**
 118      * Create a pointer {@code LayoutType} from this instance.
 119      * @return the pointer {@code LayoutType}.
 120      */
 121     @SuppressWarnings("unchecked")
 122     public LayoutType<Pointer<X>> pointer() {
 123         return new LayoutType<>(Address.ofLayout(64, layout), References.ofPointer(this));
 124     }
 125 
 126     /**
 127      * Create a {@code LayoutType} from the {@code boolean} Java primitive carrier and given layout.
 128      * @param layout the layout.
 129      * @return the {@code LayoutType}.
 130      */
 131     public static LayoutType<Boolean> ofBoolean(Layout layout) {
 132         return new LayoutType<>(layout, References.ofBoolean);
 133     }
 134 
 135     /**
 136      * Create a {@code LayoutType} from the {@code char} Java primitive carrier and given layout.
 137      * @param layout the layout.
 138      * @return the {@code LayoutType}.
 139      */
 140     public static LayoutType<Character> ofChar(Layout layout) {
 141         return new LayoutType<>(layout, References.ofChar);
 142     }
 143 
 144     /**
 145      * Create a {@code LayoutType} from the {@code byte} Java primitive carrier and given layout.
 146      * @param layout the layout.
 147      * @return the {@code LayoutType}.
 148      */
 149     public static LayoutType<Byte> ofByte(Layout layout) {
 150         return new LayoutType<>(layout, References.ofByte);
 151     }
 152 
 153     /**
 154      * Create a {@code LayoutType} from the {@code short} Java primitive carrier and given layout.
 155      * @param layout the layout.
 156      * @return the {@code LayoutType}.
 157      */
 158     public static LayoutType<Short> ofShort(Layout layout) {
 159         return new LayoutType<>(layout, References.ofShort);
 160     }
 161 
 162     /**
 163      * Create a {@code LayoutType} from the {@code int} Java primitive carrier and given layout.
 164      * @param layout the layout.
 165      * @return the {@code LayoutType}.
 166      */
 167     public static LayoutType<Integer> ofInt(Layout layout) {
 168         return new LayoutType<>(layout, References.ofInt);
 169     }
 170 
 171     /**
 172      * Create a {@code LayoutType} from the {@code float} Java primitive carrier and given layout.
 173      * @param layout the layout.
 174      * @return the {@code LayoutType}.
 175      */
 176     public static LayoutType<Float> ofFloat(Layout layout) {
 177         return new LayoutType<>(layout, References.ofFloat);
 178     }
 179 
 180     /**
 181      * Create a {@code LayoutType} from the {@code long} Java primitive carrier and given layout.
 182      * @param layout the layout.
 183      * @return the {@code LayoutType}.
 184      */
 185     public static LayoutType<Long> ofLong(Layout layout) {
 186         return new LayoutType<>(layout, References.ofLong);
 187     }
 188 
 189     /**
 190      * Create a {@code LayoutType} from the {@code double} Java primitive carrier and given layout.
 191      * @param layout the layout.
 192      * @return the {@code LayoutType}.
 193      */
 194     public static LayoutType<Double> ofDouble(Layout layout) {
 195         return new LayoutType<>(layout, References.ofDouble);
 196     }
 197 
 198     /**
 199      * Create a carrier-less {@code LayoutType} from given layout.
 200      * @param layout the layout.
 201      * @return the {@code LayoutType}.
 202      */
 203     public static LayoutType<?> ofVoid(Layout layout) {
 204         return new LayoutType<>(layout, null) {
 205             @Override
 206             public MethodHandle getter() throws UnsupportedOperationException {
 207                 throw new UnsupportedOperationException();
 208             }
 209 
 210             @Override
 211             public MethodHandle setter() throws UnsupportedOperationException {
 212                 throw new UnsupportedOperationException();
 213             }
 214         };
 215     }
 216 
 217     /**
 218      * Create a {@code LayoutType} from a {@link Struct} interface carrier.
 219      * @param <T> the struct type.
 220      * @param carrier the struct carrier.
 221      * @return the {@code LayoutType}.
 222      * @throws IllegalArgumentException if the given carrier is not annotated with the {@link java.nicl.metadata.NativeType} annotation.
 223      */
 224     public static <T extends Struct<T>> LayoutType<T> ofStruct(Class<T> carrier) throws IllegalArgumentException {
 225         NativeType nativeStruct = carrier.getAnnotation(NativeType.class);
 226         if (nativeStruct == null) {
 227             throw new IllegalArgumentException("Not a struct type!");
 228         }
 229         Group type = (Group) new DescriptorParser(nativeStruct.layout()).parseLayout().findFirst().get();
 230         return new LayoutType<>(type, References.ofStruct(carrier));
 231     }
 232 }
--- EOF ---