1 /*
  2  * Copyright (c) 2024, 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 package optkl.ifacemapper;
 26 
 27 
 28 
 29 import optkl.util.carriers.ArenaCarrier;
 30 import optkl.util.carriers.LookupCarrier;
 31 
 32 import java.lang.foreign.Arena;
 33 import java.lang.foreign.GroupLayout;
 34 import java.lang.foreign.MemoryLayout;
 35 import java.lang.foreign.MemorySegment;
 36 import java.lang.foreign.SequenceLayout;
 37 import java.lang.foreign.StructLayout;
 38 import java.lang.foreign.ValueLayout;
 39 import java.lang.invoke.MethodHandle;
 40 import java.lang.invoke.MethodHandles;
 41 import java.util.Objects;
 42 import java.util.Optional;
 43 import java.util.OptionalLong;
 44 import java.util.function.Function;
 45 import java.util.stream.Stream;
 46 
 47 /**
 48  * A segment mapper can project memory segment onto and from class instances.
 49  * <p>
 50  * More specifically, a segment mapper can project a backing
 51  * {@linkplain MemorySegment MemorySegment} into new {@link Record} instances or new
 52  * instances that implements an interface by means of matching the names of the record
 53  * components or interface methods with the names of member layouts in a group layout.
 54  * A segment mapper can also be used in the other direction, where records and interface
 55  * implementing instances can be used to update a target memory segment. By using any of
 56  * the {@linkplain #map(Class, Function) map} operations, segment mappers can be
 57  * used to map between memory segments and additional Java types other than record and
 58  * interfaces (such as JavaBeans).
 59  *
 60  * <p>
 61  * In short, a segment mapper finds, for each record component or interface method,
 62  * a corresponding member layout with the same name in the group layout. There are some
 63  * restrictions on the record component type and the corresponding member layout type
 64  * (e.g. a record component of type {@code int} can only be matched with a member layout
 65  * having a carrier type of {@code int.class} (such as {@link ValueLayout#JAVA_INT})).
 66  * <p>
 67  * Using the member layouts (e.g. observing offsets and
 68  * {@link java.nio.ByteOrder byte ordering}), a number of extraction methods are then
 69  * identified for all the record components or interface methods and these are stored
 70  * internally in the segment mapper.
 71  *
 72  * <h2 id="mapping-kinds">Mapping kinds</h2>
 73  * <p>
 74  * Segment mappers can be of two fundamental kinds;
 75  * <ul>
 76  *     <li>Record</li>
 77  *     <li>Interface</li>
 78  * </ul>
 79  * <p>
 80  * The characteristics of the mapper kinds are summarized in the following table:
 81  *
 82  * <blockquote><table class="plain">
 83  * <caption style="display:none">Mapper characteristics</caption>
 84  * <thead>
 85  * <tr>
 86  *     <th scope="col">Mapper kind</th>
 87  *     <th scope="col">Temporal mode</th>
 88  *     <th scope="col">Get operations</th>
 89  *     <th scope="col">Set operations</th>
 90  *     <th scope="col">Segment access</th>
 91  * </tr>
 92  * </thead>
 93  * <tbody>
 94  * <tr><th scope="row" style="font-weight:normal">Record</th>
 95  *     <td style="text-align:center;">Eager</td>
 96  *     <td style="text-align:center;">Extract all component values from the source segment, build the record</td>
 97  *     <td style="text-align:center;">Write all component values to the target segment</td>
 98  *     <td style="text-align:center;">N/A</td></tr>
 99  * <tr><th scope="row" style="font-weight:normal">Interface</th>
100  *     <td style="text-align:center;">Lazy</td>
101  *     <td style="text-align:center;">Wrap the source segment into a new interface instance</td>
102  *     <td style="text-align:center;">Copy the relevant values from the initial source segment into the target segment</td>
103  *     <td style="text-align:center;">via <code>SegmentMapper::segment</code></td></tr>
104  * </tbody>
105  * </table></blockquote>
106  *
107  * <h2 id="mapping-records">Mapping Records</h2>
108  * <p>
109  * The example below shows how to extract an instance of a public
110  * <em>{@code Point} record class</em> from a {@link MemorySegment} and vice versa:
111  * {@snippet lang = java:
112  *
113  *  static final GroupLayout POINT = MemoryLayout.structLayout(JAVA_INT.withName("x"), JAVA_INT.withName("y"));
114  *  public record Point(int x, int y){}
115  *  //...
116  *  MemorySegment segment = MemorySegment.ofArray(new int[]{3, 4, 0, 0});
117  *
118  *  // Obtain a SegmentMapper for the Point record type
119  *  SegmentMapper<Point> recordMapper = SegmentMapper.ofRecord(Point.class, POINT);
120  *
121  *  // Extracts a new Point record from the provided MemorySegment
122  *  Point point = recordMapper.get(segment); // Point[x=3, y=4]
123  *
124  *  // Writes the Point record to another MemorySegment
125  *  MemorySegment otherSegment = Arena.ofAuto().allocate(MemoryLayout.sequenceLayout(2, POINT));
126  *  recordMapper.setAtIndex(otherSegment, 1, point); // segment: 0, 0, 3, 4
127  *}
128  * <p>
129  * Boxing, widening, narrowing and general type conversion must be explicitly handled by
130  * user code. In the following example, the above {@code Point} (using primitive
131  * {@code int x} and {@code int y} coordinates) are explicitly mapped to a narrowed
132  * point type (instead using primitive {@code byte x} and {@code byte y} coordinates):
133  * <p>
134  * {@snippet lang = java:
135  * public record NarrowedPoint(byte x, byte y) {
136  *
137  *     static NarrowedPoint fromPoint(Point p) {
138  *         return new NarrowedPoint((byte) p.x, (byte) p.y);
139  *     }
140  *
141  *     static Point toPoint(NarrowedPoint p) {
142  *         return new Point(p.x, p.y);
143  *     }
144  *
145  * }
146  *
147  * SegmentMapper<NarrowedPoint> narrowedPointMapper =
148  *         SegmentMapper.ofRecord(Point.class, POINT)              // SegmentMapper<Point>
149  *         .map(NarrowedPoint.class, NarrowedPoint::fromPoint, NarrowedPoint::toPoint); // SegmentMapper<NarrowedPoint>
150  *
151  * // Extracts a new NarrowedPoint from the provided MemorySegment
152  * NarrowedPoint narrowedPoint = narrowedPointMapper.get(segment); // NarrowedPoint[x=3, y=4]
153  *}
154  *
155  * <h2 id="mapping-interfaces">Mapping Interfaces</h2>
156  * <p>
157  * Here is another example showing how to extract an instance of a public
158  * <em>interface with an external segment</em>:
159  * {@snippet lang = java:
160  *
161  *  static final GroupLayout POINT = MemoryLayout.structLayout(JAVA_INT.withName("x"), JAVA_INT.withName("y"));
162  *
163  *  public interface Point {
164  *       int x();
165  *       void x(int x);
166  *       int y();
167  *       void y(int x);
168  *  }
169  *
170  *  //...
171  *
172  *  MemorySegment segment = MemorySegment.ofArray(new int[]{3, 4, 0, 0});
173  *
174  *  SegmentMapper<Point> mapper = SegmentMapper.of(MethodHandles.lookup(), Point.class, POINT);
175  *
176  *  // Creates a new Point interface instance with an external segment
177  *  Point point = mapper.get(segment); // Point[x=3, y=4]
178  *  point.x(6); // Point[x=6, y=4]
179  *  point.y(8); // Point[x=6, y=8]
180  *
181  *  MemorySegment otherSegment = Arena.ofAuto().allocate(MemoryLayout.sequenceLayout(2, POINT)); // otherSegment: 0, 0, 0, 0
182  *  mapper.setAtIndex(otherSegment, 1, point); // segment: 0, 0, 6, 8
183  *}
184  * }
185  * <p>
186  * Boxing, widening, narrowing and general type conversion must be explicitly handled
187  * by user code. In the following example, the above {@code PointAccessor} interface
188  * (using primitive {@code int x} and {@code int y} coordinates) are explicitly mapped to
189  * a narrowed point type (instead using primitive {@code byte x} and
190  * {@code byte y} coordinates):
191  * <p>
192  * {@snippet lang = java:
193  * interface NarrowedPointAccessor {
194  *    byte x();
195  *    void x(byte x);
196  *    byte y();
197  *    void y(byte y);
198  *
199  *    static NarrowedPointAccessor fromPointAccessor(PointAccessor pa) {
200  *        return new NarrowedPointAccessor() {
201  *            @Override public byte x()       { return (byte)pa.x(); }
202  *            @Override public void x(byte x) { pa.x(x); }
203  *            @Override public byte y()       { return (byte) pa.y();}
204  *            @Override public void y(byte y) { pa.y(y); }
205  *       };
206  *    }
207  *
208  * }
209  *
210  * SegmentMapper<NarrowedPointAccessor> narrowedPointMapper =
211  *          // SegmentMapper<PointAccessor>
212  *           SegmentMapper.ofInterface(MethodHandles.lookup(), PointAccessor.class, POINT)
213  *                   // SegmentMapper<NarrowedPointAccessor>
214  *                  .map(NarrowedPointAccessor.class, NarrowedPointAccessor::fromPointAccessor);
215  *
216  * MemorySegment segment = MemorySegment.ofArray(new int[]{3, 4});
217  *
218  * // Creates a new NarrowedPointAccessor from the provided MemorySegment
219  * NarrowedPointAccessor narrowedPointAccessor = narrowedPointMapper.get(segment); // NarrowedPointAccessor[x=3, y=4]
220  *
221  * MemorySegment otherSegment = Arena.ofAuto().allocate(MemoryLayout.sequenceLayout(2, POINT));
222  * narrowedPointMapper.setAtIndex(otherSegment, 1, narrowedPointAccessor); // otherSegment = 0, 0, 3, 4
223  *}
224  *
225  * <h2 id="segment-exposure">Backing segment exposure</h2>
226  * <p>
227  * Implementations of interfaces that are obtained via segment mappers can be made to
228  * reveal the underlying memory segment and memory segment offset. This is useful when
229  * modelling structs that are passed and/or received by native calls:
230  * <p>
231  * {@snippet lang = java:
232  * static final GroupLayout POINT = MemoryLayout.structLayout(JAVA_INT.withName("x"), JAVA_INT.withName("y"));
233  *
234  * public interface PointAccessor {
235  *     int x();
236  *     void x(int x);
237  *     int y();
238  *     void y(int x);
239  * }
240  *
241  * static double nativeDistance(MemorySegment pointStruct) {
242  *     // Calls a native method
243  *     // ...
244  * }
245  *
246  * public static void main(String[] args) {
247  *
248  *
249  *
250  *     try (Arena arena = Arena.ofConfined()){
251  *      SegmentMapper<PointAccessor> mapper =
252  *  *             SegmentMapper.of(arena,MethodHandles.lookup(), PointAccessor.class, POINT);
253  *         // Creates an interface mapper backed by an internal segment
254  *         PointAccessor point = mapper.get(arena);
255  *         point.x(3);
256  *         point.y(4);
257  *
258  *         // Pass the backing internal segment to a native method
259  *         double distance = nativeDistance(mapper.segment(point).orElseThrow()); // 5
260  *     }
261  *
262  * }
263  *}
264  *
265  * <h2 id="formal-mapping">Formal mapping description</h2>
266  * <p>
267  * Components and layouts are matched with respect to their name and the exact return type and/or
268  * the exact parameter types. No widening or narrowing is employed.
269  *
270  * <h2 id="restrictions">Restrictions</h2>
271  * <p>
272  * Generic interfaces need to have their generic type parameters (if any)
273  * know at compile time. This applies to all extended interfaces recursively.
274  * <p>
275  * Interfaces and records must not implement (directly and/or via inheritance) more than
276  * one abstract method with the same name and erased parameter types. Hence, covariant
277  * overriding is not supported.
278  *
279  * @param <T> the type this mapper converts MemorySegments from and to.
280  * @implSpec Implementations of this interface are immutable, thread-safe and
281  * <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
282  * @since 23
283  */
284 
285 // Todo: Map components to MemorySegment (escape hatch)
286 // Todo: How do we handle "extra" setters for interfaces? They should not append
287 
288 // Cerializer
289 // Todo: Check all exceptions in JavaDocs: See TestScopedOperations
290 // Todo: Consider generating a graphics rendering.
291 // Todo: Add in doc that getting via an AddressValue will return a MS managed by Arena.global()
292 // Todo: Provide safe sharing across threads (e.g. implement a special Interface with piggybacking/volatile access)
293 // Todo: Prevent several variants in a record from being mapped to a union (otherwise, which will "win" when writing?)
294 // Todo: There seams to be a problem with the ByteOrder in the mapper. See TestJepExamplesUnions
295 // Todo: Let SegmentMapper::getHandle and ::setHandle return the sharp types (e.g. Point) see MethodHandles::exactInvoker
296 
297 // Done: The generated interface classes should be @ValueBased
298 // Done: Python "Pandas" (tables), Tabular access from array, Joins etc. <- TEST
299 //       -> See TestDataProcessingRecord and TestDataProcessingInterface
300 // No: ~map() can be dropped in favour of "manual mapping"~
301 // Done: Interfaces with internal segments should be directly available via separate factory methods
302 //       -> Fixed via SegmentMapper::create
303 // Done: Discuss if an exception is thrown in one of the sub-setters... This means partial update of the MS
304 //       This can be fixed using double-buffering. Maybe provide a scratch segment somehow that tracks where writes
305 //       has been made (via a separate class BufferedMapper?)
306 //       -> Fixed via TestInterfaceMapper::doubleBuffered
307 public interface SegmentMapper<T>  extends ArenaCarrier, LookupCarrier {
308 
309     /**
310      * {@return the type that this mapper is mapping to and from}
311      */
312     Class<T> type();
313 
314     /**
315      * {@return the original {@link GroupLayout } that this mapper is using to map
316      * record components or interface methods}
317      * <p>
318      * Composed segment mappers (obtained via either the {@link SegmentMapper#map(Class, Function)}
319      * or the {@link SegmentMapper#map(Class, Function)} will still return the
320      * group layout from the <em>original</em> SegmentMapper.
321      */
322     GroupLayout layout();
323 
324     BoundSchema<?> boundSchema();
325     // Convenience methods
326 
327     /**
328      * {@return a new instance of type T projected at an internal {@code segment} at
329      * offset zero created by means of invoking the provided {@code arena}}
330      * <p>
331      * Calling this method is equivalent to the following code:
332      * {@snippet lang = java:
333      *    get(arena.allocate(layout()));
334      * }
335      *
336 
337      * @throws IllegalStateException     if the {@linkplain MemorySegment#scope() scope}
338      * associated with the provided segment is not
339      * {@linkplain MemorySegment.Scope#isAlive() alive}
340      * @throws WrongThreadException      if this method is called from a thread {@code T},
341      * such that {@code isAccessibleBy(T) == false}
342      * @throws IllegalArgumentException  if the access operation is
343      * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
344      * of the {@link #layout()}
345      * @throws IndexOutOfBoundsException if
346      * {@code layout().byteSize() > segment.byteSize()}
347      */
348 
349     default T allocate(BoundSchema<?> boundSchema) {
350         if (boundSchema == null) {
351             throw new IllegalStateException("No bound Schema provided");
352         }
353         //System.out.println("Alloc 16 byte aligned layout + 16 bytes padded to next 16 bytes "+byteSize+"=>"+extendedByteSizePaddedTo16Bytes);
354         var segment = arena().allocate(BufferState.getLayoutSizeAfterPadding(layout()) + BufferState.byteSize(), BufferState.alignment);
355         new BufferState(segment, BufferState.getLayoutSizeAfterPadding(layout()))
356                 .setMagic()
357                 .setPtr(segment)
358                 .setLength(layout().byteSize())
359                 .setState(BufferState.NEW_STATE);
360                // .assignBits(BufferState.BIT_HOST_NEW| BufferState.BIT_HOST_DIRTY);
361         T returnValue=  get(segment, layout(), boundSchema);
362         return returnValue;
363     }
364 
365     /**
366      * {@return a new instance of type T projected at the provided
367      * external {@code segment} at offset zero}
368      * <p>
369      * Calling this method is equivalent to the following code:
370      * {@snippet lang = java:
371      *    get(segment, 0L);
372      *}
373      *
374      * @param segment the external segment to be projected to the new instance
375      * @throws IllegalStateException     if the {@linkplain MemorySegment#scope() scope}
376      *                                   associated with the provided segment is not
377      *                                   {@linkplain MemorySegment.Scope#isAlive() alive}
378      * @throws WrongThreadException      if this method is called from a thread {@code T},
379      *                                   such that {@code isAccessibleBy(T) == false}
380      * @throws IllegalArgumentException  if the access operation is
381      *                                   <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
382      *                                   of the {@link #layout()}
383      * @throws IndexOutOfBoundsException if
384      *                                   {@code layout().byteSize() > segment.byteSize()}
385      */
386     default T get(MemorySegment segment) {
387         return get(segment, 0L);
388     }
389 
390     default T get(MemorySegment segment, GroupLayout groupLayout, BoundSchema<?> boundSchema) {
391         return get(segment, groupLayout, boundSchema, 0L);
392     }
393 
394 
395     /**
396      * {@return a new sequential {@code Stream} of elements of type T}
397      * <p>
398      * Calling this method is equivalent to the following code:
399      * {@snippet lang = java:
400      * segment.elements(layout())
401      *     .map(this::get);
402      *}
403      *
404      * @param segment to carve out instances from
405      * @throws IllegalArgumentException if {@code layout().byteSize() == 0}.
406      * @throws IllegalArgumentException if {@code segment.byteSize() % layout().byteSize() != 0}.
407      * @throws IllegalArgumentException if {@code layout().byteSize() % layout().byteAlignment() != 0}.
408      * @throws IllegalArgumentException if this segment is
409      *                                  <a href="MemorySegment.html#segment-alignment">incompatible with the
410      *                                  alignment constraint</a> in the layout of this segment mapper.
411      */
412     default Stream<T> stream(MemorySegment segment) {
413         return segment.elements(layout())
414                 .map(this::get);
415     }
416 
417 
418     /**
419      * {@return a new instance of type T projected from at provided
420      * external {@code segment} at the provided {@code offset}}
421      *
422      * @param segment the external segment to be projected at the new instance
423      * @param offset  from where in the segment to project the new instance
424      * @throws IllegalStateException     if the {@linkplain MemorySegment#scope() scope}
425      *                                   associated with the provided segment is not
426      *                                   {@linkplain MemorySegment.Scope#isAlive() alive}
427      * @throws WrongThreadException      if this method is called from a thread {@code T},
428      *                                   such that {@code isAccessibleBy(T) == false}
429      * @throws IllegalArgumentException  if the access operation is
430      *                                   <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
431      *                                   of the {@link #layout()}
432      * @throws IndexOutOfBoundsException if
433      *                                   {@code offset > segment.byteSize() - layout().byteSize()}
434      */
435     @SuppressWarnings("unchecked")
436     default T get(MemorySegment segment, long offset) {
437         try {
438             return (T) getHandle()
439                     .invokeExact(segment, offset);
440         } catch (NullPointerException |
441                  IndexOutOfBoundsException |
442                  WrongThreadException |
443                  IllegalStateException |
444                  IllegalArgumentException rethrow) {
445             throw rethrow;
446         } catch (Throwable e) {
447             throw new RuntimeException("Unable to invoke getHandle() with " +
448                     "segment=" + segment +
449                     ", offset=" + offset, e);
450         }
451     }
452 
453     @SuppressWarnings("unchecked")
454     default T get(MemorySegment segment, GroupLayout layout, BoundSchema<?> boundSchema, long offset) {
455         try {
456             return (T) getHandle()
457                     .invokeExact(segment, layout, boundSchema, offset);
458         } catch (NullPointerException |
459                  IndexOutOfBoundsException |
460                  WrongThreadException |
461                  IllegalStateException |
462                  IllegalArgumentException rethrow) {
463             throw rethrow;
464         } catch (Throwable e) {
465             throw new RuntimeException("Unable to invoke getHandle() with " +
466                     "segment=" + segment +
467                     ", offset=" + offset, e);
468         }
469     }
470 
471     /**
472      * Writes the provided instance {@code t} of type T into the provided {@code segment}
473      * at offset zero.
474      * <p>
475      * Calling this method is equivalent to the following code:
476      * {@snippet lang = java:
477      *    set(segment, 0L, t);
478      *}
479      *
480      * @param segment in which to write the provided {@code t}
481      * @param t       instance to write into the provided segment
482      * @throws IllegalStateException         if the {@linkplain MemorySegment#scope() scope}
483      *                                       associated with this segment is not
484      *                                       {@linkplain MemorySegment.Scope#isAlive() alive}
485      * @throws WrongThreadException          if this method is called from a thread {@code T},
486      *                                       such that {@code isAccessibleBy(T) == false}
487      * @throws IllegalArgumentException      if the access operation is
488      *                                       <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
489      *                                       of the {@link #layout()}
490      * @throws IndexOutOfBoundsException     if {@code layout().byteSize() > segment.byteSize()}
491      * @throws UnsupportedOperationException if this segment is
492      *                                       {@linkplain MemorySegment#isReadOnly() read-only}
493      * @throws UnsupportedOperationException if {@code value} is not a
494      *                                       {@linkplain MemorySegment#isNative() native} segment
495      * @throws IllegalArgumentException      if an array length does not correspond to the
496      *                                       {@linkplain SequenceLayout#elementCount() element count} of a sequence layout
497      * @throws NullPointerException          if a required parameter is {@code null}
498      */
499     default void set(MemorySegment segment, T t) {
500         set(segment, 0L, t);
501     }
502 
503     /**
504      * Writes the provided {@code t} instance of type T into the provided {@code segment}
505      * at the provided {@code index} scaled by the {@code layout().byteSize()}}.
506      * <p>
507      * Calling this method is equivalent to the following code:
508      * {@snippet lang = java:
509      *    set(segment, layout().byteSize() * index, t);
510      *}
511      *
512      * @param segment in which to write the provided {@code t}
513      * @param index   a logical index, the offset in bytes (relative to the provided
514      *                segment address) at which the access operation will occur can be
515      *                expressed as {@code (index * layout().byteSize())}
516      * @param t       instance to write into the provided segment
517      * @throws IllegalStateException         if the {@linkplain MemorySegment#scope() scope}
518      *                                       associated with this segment is not
519      *                                       {@linkplain MemorySegment.Scope#isAlive() alive}
520      * @throws WrongThreadException          if this method is called from a thread {@code T},
521      *                                       such that {@code isAccessibleBy(T) == false}
522      * @throws IllegalArgumentException      if the access operation is
523      *                                       <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
524      *                                       of the {@link #layout()}
525      * @throws IndexOutOfBoundsException     if {@code offset > segment.byteSize() - layout.byteSize()}
526      * @throws UnsupportedOperationException if this segment is
527      *                                       {@linkplain MemorySegment#isReadOnly() read-only}
528      * @throws UnsupportedOperationException if {@code value} is not a
529      *                                       {@linkplain MemorySegment#isNative() native} segment
530      * @throws IllegalArgumentException      if an array length does not correspond to the
531      *                                       {@linkplain SequenceLayout#elementCount() element count} of a sequence layout
532      * @throws NullPointerException          if a required parameter is {@code null}
533      */
534     // default void setAtIndex(MemorySegment segment, long index, T t) {
535     //    set(segment, layout().byteSize() * index, t);
536     //  }
537 
538     /**
539      * Writes the provided instance {@code t} of type T into the provided {@code segment}
540      * at the provided {@code offset}.
541      *
542      * @param segment in which to write the provided {@code t}
543      * @param offset  offset in bytes (relative to the provided segment address) at which
544      *                this access operation will occur
545      * @param t       instance to write into the provided segment
546      * @throws IllegalStateException         if the {@linkplain MemorySegment#scope() scope}
547      *                                       associated with this segment is not
548      *                                       {@linkplain MemorySegment.Scope#isAlive() alive}
549      * @throws WrongThreadException          if this method is called from a thread {@code T},
550      *                                       such that {@code isAccessibleBy(T) == false}
551      * @throws IllegalArgumentException      if the access operation is
552      *                                       <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
553      *                                       of the {@link #layout()}
554      * @throws IndexOutOfBoundsException     if {@code offset > segment.byteSize() - layout.byteSize()}
555      * @throws UnsupportedOperationException if
556      *                                       this segment is {@linkplain MemorySegment#isReadOnly() read-only}
557      * @throws UnsupportedOperationException if
558      *                                       {@code value} is not a {@linkplain MemorySegment#isNative() native} segment // Todo: only for pointers
559      * @throws IllegalArgumentException      if an array length does not correspond to the
560      *                                       {@linkplain SequenceLayout#elementCount() element count} of a sequence layout
561      * @throws NullPointerException          if a required parameter is {@code null}
562      */
563     default void set(MemorySegment segment, long offset, T t) {
564         try {
565             setHandle()
566                     .invokeExact(segment, offset, (Object) t);
567         } catch (IndexOutOfBoundsException |
568                  WrongThreadException |
569                  IllegalStateException |
570                  IllegalArgumentException |
571                  UnsupportedOperationException |
572                  NullPointerException rethrow) {
573             throw rethrow;
574         } catch (Throwable e) {
575             throw new RuntimeException("Unable to invoke setHandle() with " +
576                     "segment=" + segment +
577                     ", offset=" + offset +
578                     ", t=" + t, e);
579         }
580     }
581 
582     // Basic methods
583 
584     /**
585      * {@return a method handle that returns new instances of type T projected at
586      * a provided external {@code MemorySegment} at a provided {@code long} offset}
587      * <p>
588      * The returned method handle has the following characteristics:
589      * <ul>
590      *     <li>its return type is {@code T};</li>
591      *     <li>it has a leading parameter of type {@code MemorySegment}
592      *         corresponding to the memory segment to be accessed</li>
593      *     <li>it has a trailing {@code long} parameter, corresponding to
594      *         the base offset</li>
595      * </ul>
596      *
597      * @see #get(MemorySegment, long)
598      */
599     MethodHandle getHandle();
600 
601     /**
602      * {@return a method handle that writes a provided instance of type T into
603      * a provided {@code MemorySegment} at a provided {@code long} offset}
604      * <p>
605      * The returned method handle has the following characteristics:
606      * <ul>
607      *     <li>its return type is void;</li>
608      *     <li>it has a leading parameter of type {@code MemorySegment}
609      *         corresponding to the memory segment to be accessed</li>
610      *     <li>it has a following {@code long} parameter, corresponding to
611      *         the base offset</li>
612      *     <li>it has a trailing {@code T} parameter, corresponding to
613      *         the value to set</li>
614      * </ul>
615      *
616      * @see #set(MemorySegment, long, Object)
617      */
618     MethodHandle setHandle();
619 
620     /**
621      * {@return a new segment mapper that would apply the provided {@code toMapper} after
622      * performing get operations on this segment mapper and that would throw an
623      * {@linkplain UnsupportedOperationException} for set operations if this
624      * segment mapper is a record mapper}
625      * <p>
626      * It should be noted that the type R can represent almost any class and is not
627      * restricted to records and interfaces.
628      * <p>
629      * Interface segment mappers returned by this method does not support
630      * {@linkplain #set(MemorySegment, Object) set} operations.
631      *
632      * @param newType  the new type the returned mapper shall use
633      * @param toMapper to apply after get operations on this segment mapper
634      * @param <R>      the type of the new segment mapper
635      */
636     <R> SegmentMapper<R> map(Class<R> newType,
637                              Function<? super T, ? extends R> toMapper);
638 
639     /**
640      * {@return the backing segment of the provided {@code source},
641      * or, if no backing segment exists, {@linkplain Optional#empty()}}
642      * <p>
643      * Interfaces obtained from segment mappers have backing segments. Records obtained
644      * from segment mappers do not.
645      *
646      * @param source from which to extract the backing segment
647      */
648     default Optional<MemorySegment> segment(T source) {
649         Objects.requireNonNull(source);
650         return Optional.empty();
651     }
652 
653     /**
654      * {@return the offset in the backing segment of the provided {@code source},
655      * or, if no backing segment exists, {@linkplain OptionalLong#empty()}}
656      * <p>
657      * Interfaces obtained from segment mappers have backing segments. Records obtained
658      * from segment mappers do not.
659      *
660      * @param source from which to extract the backing segment
661      */
662     default OptionalLong offset(T source) {
663         Objects.requireNonNull(source);
664         return OptionalLong.empty();
665     }
666 
667     /**
668      * {@return a segment mapper that maps {@linkplain MemorySegment memory segments}
669      * to the provided interface {@code type} using the provided {@code layout}
670      * and using the provided {@code lookup}}
671      *
672      * @param lookup to use when performing reflective analysis on the
673      *               provided {@code type}
674      * @param type   to map memory segment from and to
675      * @param layout to be used when mapping the provided {@code type}
676      * @param <T>    the type the returned mapper converts MemorySegments from and to
677      * @throws IllegalArgumentException if the provided {@code type} is not an interface
678      * @throws IllegalArgumentException if the provided {@code type} is a hidden interface
679      * @throws IllegalArgumentException if the provided {@code type} is a sealed interface
680      * @throws IllegalArgumentException if the provided interface {@code type} directly
681      *                                  declares any generic type parameter
682      * @throws IllegalArgumentException if the provided interface {@code type} cannot be
683      *                                  reflectively analysed using the provided {@code lookup}
684      * @throws IllegalArgumentException if the provided interface {@code type} contains
685      *                                  methods for which there are no exact mapping (of names and types) in
686      *                                  the provided {@code layout} or if the provided {@code type} is not public or
687      *                                  if the method is otherwise unable to create a segment mapper as specified above
688      * @implNote The order in which methods appear (e.g. in the {@code toString} method)
689      * is derived from the provided {@code layout}.
690      * @implNote The returned class can be a
691      * <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
692      * class; programmers should treat instances that are
693      * {@linkplain Object#equals(Object) equal} as interchangeable and should
694      * not use instances for synchronization, or unpredictable behavior may
695      * occur. For example, in a future release, synchronization may fail.
696      * @implNote The returned class can be a {@linkplain Class#isHidden() hidden} class.
697      */
698     static <T> SegmentMapper<T> of(Arena arena,MethodHandles.Lookup lookup,
699                                    Class<T> type,
700                                    GroupLayout layout) {
701         Objects.requireNonNull(lookup);
702         MapperUtil.requireImplementableInterfaceType(type);
703         Objects.requireNonNull(layout);
704         return SegmentInterfaceMapper.create(arena,lookup, type, layout, null);
705     }
706 
707     static <T extends MappableIface> SegmentMapper<T> of(Arena arena,MethodHandles.Lookup lookup, Class<T> type, GroupLayout layout, BoundSchema<?> boundSchema) {
708         Objects.requireNonNull(lookup);
709         MapperUtil.requireImplementableInterfaceType(type);
710         Objects.requireNonNull(layout);
711         return SegmentInterfaceMapper.create(arena,lookup, type, layout, boundSchema);
712 
713     }
714 
715 
716     static <T> SegmentMapper<T> of(Arena arena,MethodHandles.Lookup lookup,
717                                    Class<T> type,
718                                    MemoryLayout... elements) {
719 
720         StructLayout structlayout = MemoryLayout.structLayout(elements).withName(type.getSimpleName());
721         return of(arena,lookup, type, structlayout);
722     }
723 
724 
725     /**
726      * Interfaces extending this interface will be provided
727      * with additional methods for discovering the backing
728      * memory segment and offset used as the backing storage.
729      */
730     interface Discoverable {
731 
732         /**
733          * {@return the backing segment of this instance}
734          */
735         MemorySegment segment();
736 
737         /**
738          * {@return the backing segment of this instance}
739          */
740         MemoryLayout layout();
741 
742         /**
743          * {@return the offset in the backing segment of this instance}
744          */
745         long offset();
746     }
747 
748 }