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