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