2021-09-26 19:11:29 +00:00
( ns coffi.mem
2024-09-30 16:17:04 +00:00
" Functions for managing native allocations , memory arenas , and ( de ) serialization.
2021-09-26 19:11:29 +00:00
For any new type to be implemented , three multimethods must be overriden , but
which three depends on the native representation of the type.
If the native representation of the type is a primitive ( whether or not other
data beyond the primitive is associated with it , as e.g. a pointer ) ,
then [ [ primitive-type ] ] must be overriden to return which primitive type it is
serialized as , then [ [ serialize* ] ] and [ [ deserialize* ] ] should be overriden.
If the native representation of the type is a composite type , like a union ,
struct , or array , then [ [ c-layout ] ] must be overriden to return the native
layout of the type , and [ [ serialize-into ] ] and [ [ deserialize-from ] ] should be
overriden to allow marshaling values of the type into and out of memory
2024-01-29 12:22:39 +00:00
segments. "
2021-09-26 19:11:29 +00:00
( :require
2022-07-07 19:15:33 +00:00
[ clojure.set :as set ]
2021-09-26 19:11:29 +00:00
[ clojure.spec.alpha :as s ] )
( :import
2022-11-11 19:53:52 +00:00
( java.lang.foreign
2023-12-27 15:14:44 +00:00
AddressLayout
Arena
2021-09-26 19:11:29 +00:00
MemoryLayout
MemorySegment
2023-12-27 15:14:44 +00:00
MemorySegment$Scope
2022-01-18 20:15:08 +00:00
SegmentAllocator
2022-04-15 14:56:38 +00:00
ValueLayout
2022-11-11 19:53:52 +00:00
ValueLayout$OfByte
ValueLayout$OfShort
ValueLayout$OfInt
ValueLayout$OfLong
ValueLayout$OfChar
ValueLayout$OfFloat
2023-12-27 15:14:44 +00:00
ValueLayout$OfDouble )
2022-11-16 22:58:20 +00:00
( java.lang.ref Cleaner )
2024-09-30 16:17:04 +00:00
( java.util.function Consumer )
2022-11-11 19:53:52 +00:00
( java.nio ByteOrder ) ) )
( set! *warn-on-reflection* true )
2021-09-26 19:11:29 +00:00
2023-12-27 15:14:44 +00:00
( defn confined-arena
" Constructs a new arena for use only in this thread.
The memory allocated within this arena is cheap to allocate , like a native
stack.
The memory allocated within this arena will be cleared once it is closed , so
it is usually a good idea to create it in a [ [ with-open ] ] clause. "
( ^ Arena [ ]
( Arena/ofConfined ) ) )
( defn shared-arena
" Constructs a new shared memory arena.
2022-11-11 20:07:38 +00:00
2023-12-27 15:14:44 +00:00
This arena can be shared across threads and memory allocated in it will only
be cleaned up once any thread accessing the arena closes it. "
( ^ Arena [ ]
( Arena/ofShared ) ) )
( defn auto-arena
" Constructs a new memory arena that is managed by the garbage collector.
The arena may be shared across threads , and all resources created with it will
be cleaned up at the same time , when all references have been collected.
2022-11-11 20:07:38 +00:00
2023-12-27 15:14:44 +00:00
This type of arena cannot be closed , and therefore should not be created in
a [ [ with-open ] ] clause. "
^ Arena [ ]
( Arena/ofAuto ) )
( defn global-arena
" Constructs the global arena , which will never reclaim its resources.
This arena may be shared across threads , but is intended mainly in cases where
memory is allocated with [ [ alloc ] ] but is either never freed or whose
management is relinquished to a native library , such as when returned from a
callback. "
^ Arena [ ]
( Arena/global ) )
2022-11-11 20:07:38 +00:00
2024-01-29 12:22:39 +00:00
( defn arena-allocator
" Constructs a [ [ SegmentAllocator ] ] from the given [ [ Arena ] ] .
This is primarily used when working with unwrapped downcall functions. When a
downcall function returns a non-primitive type , it must be provided with an
allocator. "
2024-09-30 16:17:04 +00:00
^ SegmentAllocator [ ^ Arena arena ]
2024-01-29 12:22:39 +00:00
( reify SegmentAllocator
( ^ MemorySegment allocate [ _this ^ long byte-size ^ long byte-alignment ]
2024-09-30 16:17:04 +00:00
( .allocate arena ^ long byte-size ^ long byte-alignment ) ) ) )
2022-11-11 20:07:38 +00:00
2021-09-26 19:11:29 +00:00
( defn alloc
" Allocates ` size ` bytes.
2023-12-27 15:14:44 +00:00
If an ` arena ` is provided , the allocation will be reclaimed when it is closed. "
( ^ MemorySegment [ size ] ( alloc size ( auto-arena ) ) )
( ^ MemorySegment [ size arena ] ( .allocate ^ Arena arena ( long size ) ) )
( ^ MemorySegment [ size alignment arena ] ( .allocate ^ Arena arena ( long size ) ( long alignment ) ) ) )
2021-09-26 19:11:29 +00:00
( defn alloc-with
"Allocates `size` bytes using the `allocator`."
2022-01-18 19:38:32 +00:00
( ^ MemorySegment [ allocator size ]
2021-09-26 19:11:29 +00:00
( .allocate ^ SegmentAllocator allocator ( long size ) ) )
2022-01-18 19:38:32 +00:00
( ^ MemorySegment [ allocator size alignment ]
2021-09-26 19:11:29 +00:00
( .allocate ^ SegmentAllocator allocator ( long size ) ( long alignment ) ) ) )
( defn address-of
2024-10-03 18:11:57 +00:00
"Gets the address of a given segment as a number."
2023-12-27 15:14:44 +00:00
^ long [ addressable ]
( .address ^ MemorySegment addressable ) )
2021-09-26 19:11:29 +00:00
2024-10-02 20:22:29 +00:00
( def ^ MemorySegment null
" The NULL pointer object.
While this object is safe to pass to functions which serialize to a pointer ,
it 's generally encouraged to simply pass ` nil ` . This value primarily exists to
make it easier to write custom types with a primitive pointer representation. "
MemorySegment/NULL )
2021-09-26 19:11:29 +00:00
( defn null?
"Checks if a memory address is null."
[ addr ]
2024-10-02 20:22:29 +00:00
( or ( .equals null addr ) ( not addr ) ) )
2021-09-26 19:11:29 +00:00
2021-10-05 00:20:47 +00:00
( defn address?
" Checks if an object is a memory address.
` nil ` is considered an address. "
[ addr ]
2023-12-27 15:14:44 +00:00
( or ( nil? addr ) ( instance? MemorySegment addr ) ) )
2021-10-05 00:20:47 +00:00
2021-09-26 19:11:29 +00:00
( defn slice
"Get a slice over the `segment` with the given `offset`."
2022-01-18 19:38:32 +00:00
( ^ MemorySegment [ segment offset ]
2021-09-26 19:11:29 +00:00
( .asSlice ^ MemorySegment segment ( long offset ) ) )
2022-01-18 19:38:32 +00:00
( ^ MemorySegment [ segment offset size ]
2021-09-26 19:11:29 +00:00
( .asSlice ^ MemorySegment segment ( long offset ) ( long size ) ) ) )
2024-09-30 16:17:04 +00:00
( defn reinterpret
" Reinterprets the ` segment ` as having the passed ` size ` .
If ` arena ` is passed , the scope of the ` segment ` is associated with the arena ,
as well as its access constraints. If ` cleanup ` is passed , it will be a
1 -argument function of a fresh memory segment backed by the same memory as the
returned segment which should perform any required cleanup operations. It will
be called when the ` arena ` is closed. "
( ^ MemorySegment [ ^ MemorySegment segment size ]
( .reinterpret segment ( long size ) ( auto-arena ) nil ) )
( ^ MemorySegment [ ^ MemorySegment segment size ^ Arena arena ]
( .reinterpret segment ( long size ) arena nil ) )
( ^ MemorySegment [ ^ MemorySegment segment size ^ Arena arena cleanup ]
( .reinterpret segment ( long size ) arena
( reify Consumer
( accept [ _this segment ]
( cleanup segment ) ) ) ) ) )
2021-09-26 19:11:29 +00:00
2022-04-15 14:56:38 +00:00
( defn as-segment
2024-09-30 16:17:04 +00:00
"Dereferences an `address` into a memory segment associated with the `arena` (default global)."
( ^ MemorySegment [ ^ long address ]
( MemorySegment/ofAddress address ) )
( ^ MemorySegment [ ^ long address size ]
( reinterpret ( MemorySegment/ofAddress address ) size ) )
( ^ MemorySegment [ ^ long address size ^ Arena arena ]
( reinterpret ( MemorySegment/ofAddress address ) ( long size ) arena nil ) )
( ^ MemorySegment [ ^ long address size ^ Arena arena cleanup ]
( reinterpret ( MemorySegment/ofAddress address ) ( long size ) arena cleanup ) ) )
2022-04-15 14:56:38 +00:00
2021-09-26 19:11:29 +00:00
( defn copy-segment
2022-01-18 19:38:32 +00:00
" Copies the content to ` dest ` from ` src ` .
Returns ` dest ` . "
^ MemorySegment [ ^ MemorySegment dest ^ MemorySegment src ]
2023-12-27 15:14:44 +00:00
( .copyFrom dest src ) )
2021-09-26 19:11:29 +00:00
( defn clone-segment
"Clones the content of `segment` into a new segment of the same size."
2024-09-30 16:17:04 +00:00
( ^ MemorySegment [ segment ] ( clone-segment segment ( auto-arena ) ) )
( ^ MemorySegment [ ^ MemorySegment segment ^ Arena arena ]
( copy-segment ^ MemorySegment ( alloc ( .byteSize segment ) arena ) segment ) ) )
2021-09-26 19:11:29 +00:00
( defn slice-segments
"Constructs a lazy seq of `size`-length memory segments, sliced from `segment`."
2022-01-18 19:38:32 +00:00
[ ^ MemorySegment segment size ]
( let [ num-segments ( quot ( .byteSize segment ) size ) ]
2021-09-26 19:11:29 +00:00
( map # ( slice segment ( * % size ) size )
( range num-segments ) ) ) )
2022-01-18 20:15:08 +00:00
( def ^ ByteOrder big-endian
2022-01-18 19:25:56 +00:00
" The big-endian [ [ ByteOrder ] ] .
See [ [ little-endian ] ] , [ [ native-endian ] ] . "
ByteOrder/BIG_ENDIAN )
2022-01-18 20:15:08 +00:00
( def ^ ByteOrder little-endian
2022-01-18 19:25:56 +00:00
" The little-endian [ [ ByteOrder ] ] .
See [ [ big-endian ] ] , [ [ native-endian ] ] "
ByteOrder/LITTLE_ENDIAN )
2022-01-18 20:15:08 +00:00
( def ^ ByteOrder native-endian
2022-01-18 19:25:56 +00:00
" The [ [ ByteOrder ] ] for the native endianness of the current hardware.
See [ [ big-endian ] ] , [ [ little-endian ] ] . "
( ByteOrder/nativeOrder ) )
2022-11-11 19:53:52 +00:00
( def ^ ValueLayout$OfByte byte-layout
2022-01-18 19:38:48 +00:00
"The [[MemoryLayout]] for a byte in [[native-endian]] [[ByteOrder]]."
2022-11-11 19:53:52 +00:00
ValueLayout/JAVA_BYTE )
2022-01-18 19:26:35 +00:00
2022-11-11 19:53:52 +00:00
( def ^ ValueLayout$OfShort short-layout
2022-01-18 19:38:48 +00:00
"The [[MemoryLayout]] for a c-sized short in [[native-endian]] [[ByteOrder]]."
2022-11-11 19:53:52 +00:00
ValueLayout/JAVA_SHORT )
2022-01-18 19:26:35 +00:00
2022-11-11 19:53:52 +00:00
( def ^ ValueLayout$OfInt int-layout
2022-01-18 19:38:48 +00:00
"The [[MemoryLayout]] for a c-sized int in [[native-endian]] [[ByteOrder]]."
2022-11-11 19:53:52 +00:00
ValueLayout/JAVA_INT )
2022-01-18 19:26:35 +00:00
2022-11-11 19:53:52 +00:00
( def ^ ValueLayout$OfLong long-layout
2022-01-18 19:38:48 +00:00
"The [[MemoryLayout]] for a c-sized long in [[native-endian]] [[ByteOrder]]."
2022-11-11 19:53:52 +00:00
ValueLayout/JAVA_LONG )
2022-01-18 19:26:35 +00:00
2022-11-11 19:53:52 +00:00
( def ^ ValueLayout$OfByte char-layout
2022-01-18 19:38:48 +00:00
"The [[MemoryLayout]] for a c-sized char in [[native-endian]] [[ByteOrder]]."
2022-11-11 19:53:52 +00:00
ValueLayout/JAVA_BYTE )
2022-01-18 19:26:35 +00:00
2022-11-11 19:53:52 +00:00
( def ^ ValueLayout$OfFloat float-layout
2022-01-18 19:38:48 +00:00
"The [[MemoryLayout]] for a c-sized float in [[native-endian]] [[ByteOrder]]."
2022-11-11 19:53:52 +00:00
ValueLayout/JAVA_FLOAT )
2022-01-18 19:26:35 +00:00
2022-11-11 19:53:52 +00:00
( def ^ ValueLayout$OfDouble double-layout
2022-01-18 19:38:48 +00:00
"The [[MemoryLayout]] for a c-sized double in [[native-endian]] [[ByteOrder]]."
2022-11-11 19:53:52 +00:00
ValueLayout/JAVA_DOUBLE )
2022-01-18 19:26:35 +00:00
2024-01-29 12:22:39 +00:00
( def ^ AddressLayout pointer-layout
2022-01-18 19:38:48 +00:00
"The [[MemoryLayout]] for a native pointer in [[native-endian]] [[ByteOrder]]."
2022-11-11 19:53:52 +00:00
ValueLayout/ADDRESS )
2022-01-18 19:26:35 +00:00
2022-01-19 17:00:57 +00:00
( def ^ long short-size
2022-01-19 16:56:46 +00:00
"The size in bytes of a c-sized short."
( .byteSize short-layout ) )
2022-01-19 17:00:57 +00:00
( def ^ long int-size
2022-01-19 16:56:46 +00:00
"The size in bytes of a c-sized int."
( .byteSize int-layout ) )
2022-01-19 17:00:57 +00:00
( def ^ long long-size
2022-01-19 16:56:46 +00:00
"The size in bytes of a c-sized long."
( .byteSize long-layout ) )
2022-01-19 17:00:57 +00:00
( def ^ long float-size
2022-01-19 16:56:46 +00:00
"The size in bytes of a c-sized float."
( .byteSize float-layout ) )
2022-01-19 17:00:57 +00:00
( def ^ long double-size
2022-01-19 16:56:46 +00:00
"The size in bytes of a c-sized double."
( .byteSize double-layout ) )
2022-01-19 17:00:57 +00:00
( def ^ long pointer-size
2022-01-19 16:56:46 +00:00
"The size in bytes of a c-sized pointer."
( .byteSize pointer-layout ) )
2022-01-19 17:00:57 +00:00
( def ^ long short-alignment
2022-01-19 16:56:46 +00:00
"The alignment in bytes of a c-sized short."
( .byteAlignment short-layout ) )
2022-01-19 17:00:57 +00:00
( def ^ long int-alignment
2022-01-19 16:56:46 +00:00
"The alignment in bytes of a c-sized int."
( .byteAlignment int-layout ) )
2022-01-19 17:00:57 +00:00
( def ^ long long-alignment
2022-01-19 16:56:46 +00:00
"The alignment in bytes of a c-sized long."
( .byteAlignment long-layout ) )
2022-01-19 17:00:57 +00:00
( def ^ long float-alignment
2022-01-19 16:56:46 +00:00
"The alignment in bytes of a c-sized float."
( .byteAlignment float-layout ) )
2022-01-19 17:00:57 +00:00
( def ^ long double-alignment
2022-01-19 16:56:46 +00:00
"The alignment in bytes of a c-sized double."
( .byteAlignment double-layout ) )
2022-01-19 17:00:57 +00:00
( def ^ long pointer-alignment
2022-01-19 16:56:46 +00:00
"The alignment in bytes of a c-sized pointer."
( .byteAlignment pointer-layout ) )
2022-01-18 19:39:04 +00:00
( defn read-byte
"Reads a [[byte]] from the `segment`, at an optional `offset`."
{ :inline
( fn read-byte-inline
( [ segment ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ^ ValueLayout$OfByte byte-layout 0 ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ^ ValueLayout$OfByte byte-layout offset# ) ) ) ) }
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ]
2022-11-11 19:53:52 +00:00
( .get segment ^ ValueLayout$OfByte byte-layout 0 ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset ]
2022-11-11 19:53:52 +00:00
( .get segment ^ ValueLayout$OfByte byte-layout offset ) ) )
2022-01-18 19:39:04 +00:00
( defn read-short
" Reads a [ [ short ] ] from the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn read-short-inline
( [ segment ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ^ ValueLayout$OfShort short-layout 0 ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ^ ValueLayout$OfShort short-layout offset# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset byte-order ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ( .withOrder ^ ValueLayout$OfShort short-layout ^ ByteOrder byte-order# ) offset# ) ) ) ) }
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ]
2022-11-11 19:53:52 +00:00
( .get segment ^ ValueLayout$OfShort short-layout 0 ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset ]
2022-11-11 19:53:52 +00:00
( .get segment ^ ValueLayout$OfShort short-layout offset ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order ]
2022-11-11 19:53:52 +00:00
( .get segment ( .withOrder ^ ValueLayout$OfShort short-layout byte-order ) offset ) ) )
2022-01-18 19:39:04 +00:00
( defn read-int
" Reads a [ [ int ] ] from the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn read-int-inline
( [ segment ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ^ ValueLayout$OfInt int-layout 0 ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ^ ValueLayout$OfInt int-layout offset# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset byte-order ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ( .withOrder ^ ValueLayout$OfInt int-layout ^ ByteOrder byte-order# ) offset# ) ) ) ) }
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ]
2022-11-11 19:53:52 +00:00
( .get segment ^ ValueLayout$OfInt int-layout 0 ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset ]
2022-11-11 19:53:52 +00:00
( .get segment ^ ValueLayout$OfInt int-layout offset ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order ]
2022-11-11 19:53:52 +00:00
( .get segment ( .withOrder ^ ValueLayout$OfInt int-layout byte-order ) offset ) ) )
2022-01-18 19:39:04 +00:00
( defn read-long
" Reads a [ [ long ] ] from the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn read-long-inline
( [ segment ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ^ ValueLayout$OfLong long-layout 0 ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ^ ValueLayout$OfLong long-layout offset# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset byte-order ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ( .withOrder ^ ValueLayout$OfLong long-layout ^ ByteOrder byte-order# ) offset# ) ) ) ) }
2022-01-18 19:39:04 +00:00
( ^ long [ ^ MemorySegment segment ]
2022-11-11 19:53:52 +00:00
( .get segment ^ ValueLayout$OfLong long-layout 0 ) )
2022-01-18 19:39:04 +00:00
( ^ long [ ^ MemorySegment segment ^ long offset ]
2022-11-11 19:53:52 +00:00
( .get segment ^ ValueLayout$OfLong long-layout offset ) )
2022-01-18 19:39:04 +00:00
( ^ long [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order ]
2022-11-11 19:53:52 +00:00
( .get segment ( .withOrder ^ ValueLayout$OfLong long-layout byte-order ) offset ) ) )
2022-01-18 19:39:04 +00:00
( defn read-char
"Reads a [[char]] from the `segment`, at an optional `offset`."
{ :inline
( fn read-char-inline
( [ segment ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment ]
2022-11-11 19:53:52 +00:00
( char ( Byte/toUnsignedInt ( .get ^ MemorySegment segment# ^ ValueLayout$OfByte byte-layout 0 ) ) ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset ]
2022-11-11 19:53:52 +00:00
( char ( Byte/toUnsignedInt ( .get ^ MemorySegment segment# ^ ValueLayout$OfByte byte-layout offset# ) ) ) ) ) ) }
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ]
2022-11-11 19:53:52 +00:00
( char ( Byte/toUnsignedInt ( .get segment ^ ValueLayout$OfChar byte-layout 0 ) ) ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset ]
2022-11-11 19:53:52 +00:00
( char ( Byte/toUnsignedInt ( .get segment ^ ValueLayout$OfChar byte-layout offset ) ) ) ) )
2022-01-18 19:39:04 +00:00
( defn read-float
" Reads a [ [ float ] ] from the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn read-float-inline
( [ segment ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ^ ValueLayout$OfFloat float-layout 0 ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ^ ValueLayout$OfFloat float-layout offset# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset byte-order ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ( .withOrder ^ ValueLayout$OfFloat float-layout ^ ByteOrder byte-order# ) offset# ) ) ) ) }
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ]
2022-11-11 19:53:52 +00:00
( .get segment ^ ValueLayout$OfFloat float-layout 0 ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset ]
2022-11-11 19:53:52 +00:00
( .get segment ^ ValueLayout$OfFloat float-layout offset ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order ]
2022-11-11 19:53:52 +00:00
( .get segment ( .withOrder ^ ValueLayout$OfFloat float-layout byte-order ) offset ) ) )
2022-01-18 19:39:04 +00:00
( defn read-double
" Reads a [ [ double ] ] from the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn read-double-inline
( [ segment ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ^ ValueLayout$OfDouble double-layout 0 ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ^ ValueLayout$OfDouble double-layout offset# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset byte-order ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order ]
2022-11-11 19:53:52 +00:00
( .get ^ MemorySegment segment# ( .withOrder ^ ValueLayout$OfDouble double-layout ^ ByteOrder byte-order# ) offset# ) ) ) ) }
2022-01-18 19:39:04 +00:00
( ^ double [ ^ MemorySegment segment ]
2022-11-11 19:53:52 +00:00
( .get segment ^ ValueLayout$OfDouble double-layout 0 ) )
2022-01-18 19:39:04 +00:00
( ^ double [ ^ MemorySegment segment ^ long offset ]
2022-11-11 19:53:52 +00:00
( .get segment ^ ValueLayout$OfDouble double-layout offset ) )
2022-01-18 19:39:04 +00:00
( ^ double [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order ]
2022-11-11 19:53:52 +00:00
( .get segment ( .withOrder ^ ValueLayout$OfDouble double-layout byte-order ) offset ) ) )
2022-01-18 19:39:04 +00:00
2022-01-18 21:39:49 +00:00
( defn read-address
2024-01-29 12:22:39 +00:00
"Reads an address from the `segment`, at an optional `offset`, wrapped in a [[MemorySegment]]."
2022-01-18 21:39:49 +00:00
{ :inline
( fn read-address-inline
( [ segment ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment ]
2024-01-29 12:22:39 +00:00
( .get ^ MemorySegment segment# ^ AddressLayout pointer-layout 0 ) ) )
2022-01-18 21:39:49 +00:00
( [ segment offset ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset ]
2024-01-29 12:22:39 +00:00
( .get ^ MemorySegment segment# ^ AddressLayout pointer-layout offset# ) ) ) ) }
( ^ MemorySegment [ ^ MemorySegment segment ]
( .get segment ^ AddressLayout pointer-layout 0 ) )
( ^ MemorySegment [ ^ MemorySegment segment ^ long offset ]
( .get segment ^ AddressLayout pointer-layout offset ) ) )
2022-01-18 21:39:49 +00:00
2022-01-18 19:39:04 +00:00
( defn write-byte
"Writes a [[byte]] to the `segment`, at an optional `offset`."
{ :inline
( fn write-byte-inline
( [ segment value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ^ ValueLayout$OfByte byte-layout 0 value# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ^ ValueLayout$OfByte byte-layout offset# value# ) ) ) ) }
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment value ]
2022-11-11 19:53:52 +00:00
( .set segment ^ ValueLayout$OfByte byte-layout 0 ^ byte value ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset value ]
2022-11-11 19:53:52 +00:00
( .set segment ^ ValueLayout$OfByte byte-layout offset ^ byte value ) ) )
2022-01-18 19:39:04 +00:00
( defn write-short
" Writes a [ [ short ] ] to the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn write-short-inline
( [ segment value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ^ ValueLayout$OfShort short-layout 0 value# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ^ ValueLayout$OfShort short-layout offset# value# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset byte-order value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ( .withOrder ^ ValueLayout$OfShort short-layout ^ ByteOrder byte-order# ) offset# value# ) ) ) ) }
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment value ]
2022-11-11 19:53:52 +00:00
( .set segment ^ ValueLayout$OfShort short-layout 0 ^ short value ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset value ]
2022-11-11 19:53:52 +00:00
( .set segment ^ ValueLayout$OfShort short-layout offset ^ short value ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order value ]
2022-11-11 19:53:52 +00:00
( .set segment ( .withOrder ^ ValueLayout$OfShort short-layout byte-order ) offset ^ short value ) ) )
2022-01-18 19:39:04 +00:00
( defn write-int
" Writes a [ [ int ] ] to the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn write-int-inline
( [ segment value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ^ ValueLayout$OfInt int-layout 0 value# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ^ ValueLayout$OfInt int-layout offset# value# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset byte-order value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ( .withOrder ^ ValueLayout$OfInt int-layout ^ ByteOrder byte-order# ) offset# value# ) ) ) ) }
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment value ]
2022-11-11 19:53:52 +00:00
( .set segment ^ ValueLayout$OfInt int-layout 0 ^ int value ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset value ]
2022-11-11 19:53:52 +00:00
( .set segment ^ ValueLayout$OfInt int-layout offset ^ int value ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order value ]
2022-11-11 19:53:52 +00:00
( .set segment ( .withOrder ^ ValueLayout$OfInt int-layout byte-order ) offset ^ int value ) ) )
2022-01-18 19:39:04 +00:00
( defn write-long
" Writes a [ [ long ] ] to the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn write-long-inline
( [ segment value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ^ ValueLayout$OfLong long-layout 0 value# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ^ ValueLayout$OfLong long-layout offset# value# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset byte-order value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ( .withOrder ^ ValueLayout$OfLong long-layout ^ ByteOrder byte-order# ) offset# value# ) ) ) ) }
2022-01-18 19:39:04 +00:00
( ^ long [ ^ MemorySegment segment ^ long value ]
2022-11-11 19:53:52 +00:00
( .set segment ^ ValueLayout$OfLong long-layout 0 value ) )
2022-01-18 19:39:04 +00:00
( ^ long [ ^ MemorySegment segment ^ long offset ^ long value ]
2022-11-11 19:53:52 +00:00
( .set segment ^ ValueLayout$OfLong long-layout offset value ) )
2022-01-18 19:39:04 +00:00
( ^ long [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order ^ long value ]
2022-11-11 19:53:52 +00:00
( .set segment ( .withOrder ^ ValueLayout$OfLong long-layout byte-order ) offset value ) ) )
2022-01-18 19:39:04 +00:00
( defn write-char
"Writes a [[char]] to the `segment`, at an optional `offset`."
{ :inline
( fn write-char-inline
( [ segment value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ^ ValueLayout$OfByte byte-layout 0 ( unchecked-byte ( unchecked-int value# ) ) ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ^ ValueLayout$OfByte byte-layout offset# ( unchecked-byte ( unchecked-int value# ) ) ) ) ) ) }
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment value ]
2022-04-15 14:56:38 +00:00
( .set
2022-01-18 19:39:04 +00:00
segment
;; HACK(Joshua): The Clojure runtime doesn't have an unchecked-byte cast for
;; characters, so this double cast is necessary unless I emit
;; my own bytecode with insn.
2022-11-11 19:53:52 +00:00
^ ValueLayout$OfByte byte-layout 0
2022-01-18 19:39:04 +00:00
( unchecked-byte ( unchecked-int ^ char value ) ) ) )
( [ ^ MemorySegment segment ^ long offset value ]
2022-11-11 19:53:52 +00:00
( .set segment ^ ValueLayout$OfByte byte-layout offset ( unchecked-byte ( unchecked-int ^ char value ) ) ) ) )
2022-01-18 19:39:04 +00:00
( defn write-float
" Writes a [ [ float ] ] to the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn write-float-inline
( [ segment value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ^ ValueLayout$OfFloat float-layout 0 value# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ^ ValueLayout$OfFloat float-layout offset# value# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset byte-order value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ( .withOrder ^ ValueLayout$OfFloat float-layout ^ ByteOrder byte-order# ) offset# value# ) ) ) ) }
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment value ]
2022-11-11 19:53:52 +00:00
( .set segment ^ ValueLayout$OfFloat float-layout 0 ^ float value ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset value ]
2022-11-11 19:53:52 +00:00
( .set segment ^ ValueLayout$OfFloat float-layout offset ^ float value ) )
2022-01-18 19:39:04 +00:00
( [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order value ]
2022-11-11 19:53:52 +00:00
( .set segment ( .withOrder ^ ValueLayout$OfFloat float-layout byte-order ) offset ^ float value ) ) )
2022-01-18 19:39:04 +00:00
( defn write-double
" Writes a [ [ double ] ] to the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn write-double-inline
( [ segment value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ^ ValueLayout$OfDouble double-layout 0 value# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ^ ValueLayout$OfDouble double-layout offset# value# ) ) )
2022-01-18 19:39:04 +00:00
( [ segment offset byte-order value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order
value# ~ value ]
2022-11-11 19:53:52 +00:00
( .set ^ MemorySegment segment# ( .withOrder ^ ValueLayout$OfDouble double-layout ^ ByteOrder byte-order# ) offset# value# ) ) ) ) }
2022-01-18 19:39:04 +00:00
( ^ double [ ^ MemorySegment segment ^ double value ]
2022-11-11 19:53:52 +00:00
( .set segment ^ ValueLayout$OfDouble double-layout 0 value ) )
2022-01-18 19:39:04 +00:00
( ^ double [ ^ MemorySegment segment ^ long offset ^ double value ]
2022-11-11 19:53:52 +00:00
( .set segment ^ ValueLayout$OfDouble double-layout offset value ) )
2022-01-18 19:39:04 +00:00
( ^ double [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order ^ double value ]
2022-11-11 19:53:52 +00:00
( .set segment ( .withOrder ^ ValueLayout$OfDouble double-layout byte-order ) offset value ) ) )
2022-01-18 19:39:04 +00:00
2022-01-18 21:39:49 +00:00
( defn write-address
2024-01-29 12:22:39 +00:00
"Writes the address of the [[MemorySegment]] `value` to the `segment`, at an optional `offset`."
2022-01-18 21:39:49 +00:00
{ :inline
( fn write-address-inline
( [ segment value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
value# ~ value ]
2024-01-29 12:22:39 +00:00
( .set ^ MemorySegment segment# ^ AddressLayout pointer-layout 0 ^ MemorySegment value# ) ) )
2022-01-18 21:39:49 +00:00
( [ segment offset value ]
2022-04-15 14:56:38 +00:00
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2024-01-29 12:22:39 +00:00
( .set ^ MemorySegment segment# ^ AddressLayout pointer-layout offset# ^ MemorySegment value# ) ) ) ) }
( [ ^ MemorySegment segment ^ MemorySegment value ]
( .set segment ^ AddressLayout pointer-layout 0 value ) )
( [ ^ MemorySegment segment ^ long offset ^ MemorySegment value ]
( .set segment ^ AddressLayout pointer-layout offset value ) ) )
2022-01-18 21:39:49 +00:00
2024-10-04 14:17:27 +00:00
( defn write-bytes
"Writes a [[byte]] array to the `segment`, at an optional `offset`."
{ :inline
( fn write-byte-inline
( [ segment value ]
` ( let [ segment# ~ segment
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 ^ MemorySegment segment# ^ ValueLayout$OfByte byte-layout 0 ^ int ( alength value# ) ) ) )
2024-10-04 14:17:27 +00:00
( [ segment offset value ]
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 ^ MemorySegment segment# ^ ValueLayout$OfByte byte-layout offset# ^ int ( alength value# ) ) ) ) ) }
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ bytes value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ^ ValueLayout$OfByte byte-layout 0 ( alength value ) ) )
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment offset ^ bytes value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ^ ValueLayout$OfByte byte-layout ^ long offset ^ int ( alength value ) ) ) )
2024-10-04 14:17:27 +00:00
( defn write-shorts
" Writes a [ [ short ] ] array to the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn write-shorts-inline
( [ segment value ]
` ( let [ segment# ~ segment
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 segment# ^ ValueLayout$OfShort short-layout 0 ^ int ( alength value# ) ) ) )
2024-10-04 14:17:27 +00:00
( [ segment offset value ]
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 segment# ^ ValueLayout$OfShort short-layout ^ long offset ^ int ( alength value# ) ) ) )
2024-10-04 14:17:27 +00:00
( [ segment offset byte-order value ]
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 segment# ( .withOrder ^ ValueLayout$OfShort short-layout ^ ByteOrder byte-order# ) ^ long offset ^ int ( alength value# ) ) ) ) ) }
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ shorts value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ^ ValueLayout$OfShort short-layout 0 ( alength value ) ) )
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ long offset ^ shorts value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ^ ValueLayout$OfShort short-layout ^ long offset ( alength value ) ) )
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order ^ shorts value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ( .withOrder ^ ValueLayout$OfShort short-layout byte-order ) ^ long offset ( alength value ) ) ) )
2024-10-04 14:17:27 +00:00
( defn write-ints
" Writes a [ [ int ] ] array to the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn write-ints-inline
( [ segment value ]
` ( let [ segment# ~ segment
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 segment# ^ ValueLayout$OfInt int-layout 0 ^ int ( alength value# ) )
2024-10-04 14:17:27 +00:00
) )
( [ segment offset value ]
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 segment# ^ ValueLayout$OfInt int-layout ^ long offset ^ int ( alength value# ) )
2024-10-04 14:17:27 +00:00
) )
( [ segment offset byte-order value ]
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 segment# ( .withOrder ^ ValueLayout$OfInt int-layout ^ ByteOrder byte-order# ) ^ long offset ^ int ( alength value# ) ) ) ) ) }
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ ints value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ^ ValueLayout$OfInt int-layout 0 ( alength value ) ) )
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ long offset ^ ints value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ^ ValueLayout$OfInt int-layout ^ long offset ( alength value ) ) )
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order ^ ints value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ( .withOrder ^ ValueLayout$OfInt int-layout byte-order ) ^ long offset ( alength value ) ) ) )
2024-10-04 14:17:27 +00:00
( defn write-longs
" Writes a [ [ long ] ] array to the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn write-longs-inline
( [ segment value ]
` ( let [ segment# ~ segment
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 ^ MemorySegment segment# ^ ValueLayout$OfLong long-layout 0 ^ int ( alength value# ) )
2024-10-04 14:17:27 +00:00
) )
( [ segment offset value ]
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 ^ MemorySegment segment# ^ ValueLayout$OfLong long-layout ^ long offset ^ int ( alength value# ) )
2024-10-04 14:17:27 +00:00
) )
( [ segment offset byte-order value ]
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 ^ MemorySegment segment# ( .withOrder ^ ValueLayout$OfLong long-layout ^ ByteOrder byte-order# ) ^ long offset ^ int ( alength value# ) ) ) ) ) }
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ longs value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ^ ValueLayout$OfLong long-layout 0 ^ int ( alength value ) ) )
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ long offset ^ longs value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ^ ValueLayout$OfLong long-layout ^ long offset ^ int ( alength value ) ) )
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order ^ longs value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ( .withOrder ^ ValueLayout$OfLong long-layout byte-order ) ^ long offset ^ int ( alength value ) ) ) )
2024-10-04 14:17:27 +00:00
( defn write-chars
" Writes a [ [ char ] ] array to the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn write-chars-inline
( [ segment value ]
` ( let [ segment# ~ segment
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy ( bytes ( byte-array ( map unchecked-int value# ) ) ) 0 segment# ^ ValueLayout$OfChar char-layout 0 ^ int ( alength value# ) ) ) )
2024-10-04 14:17:27 +00:00
( [ segment offset value ]
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy ( bytes ( byte-array ( map unchecked-int value# ) ) ) 0 segment# ^ ValueLayout$OfChar char-layout ^ long offset ^ int ( alength value# ) ) ) )
2024-10-04 14:17:27 +00:00
( [ segment offset byte-order value ]
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy ( bytes ( byte-array ( map unchecked-int value# ) ) ) 0 segment# ( .withOrder ^ ValueLayout$OfChar char-layout ^ ByteOrder byte-order# ) ^ long offset ^ int ( alength value# ) ) ) ) ) }
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ chars value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy ( bytes ( byte-array ( map unchecked-int value ) ) ) 0 segment ^ ValueLayout$OfChar char-layout 0 ( alength value ) ) )
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ long offset ^ chars value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy ( bytes ( byte-array ( map unchecked-int value ) ) ) 0 segment ^ ValueLayout$OfChar char-layout ^ long offset ( alength value ) ) )
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order ^ chars value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy ( bytes ( byte-array ( map unchecked-int value ) ) ) 0 segment ( .withOrder ^ ValueLayout$OfChar char-layout byte-order ) ^ long offset ( alength value ) ) ) )
2024-10-04 14:17:27 +00:00
( defn write-floats
" Writes a [ [ float ] ] array to the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn write-floats-inline
( [ segment value ]
` ( let [ segment# ~ segment
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 ^ MemorySegment segment# ^ ValueLayout$OfFloat float-layout 0 ^ int ( alength value# ) )
2024-10-04 14:17:27 +00:00
) )
( [ segment offset value ]
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 ^ MemorySegment segment# ^ ValueLayout$OfFloat float-layout ^ long offset ^ int ( alength value# ) )
2024-10-04 14:17:27 +00:00
) )
( [ segment offset byte-order value ]
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 ^ MemorySegment segment# ( .withOrder ^ ValueLayout$OfFloat float-layout ^ ByteOrder byte-order# ) ^ long offset ^ int ( alength value# ) ) ) ) ) }
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ floats value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ^ ValueLayout$OfFloat float-layout 0 ^ int ( alength value ) ) )
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ long offset ^ floats value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ^ ValueLayout$OfFloat float-layout ^ long offset ^ int ( alength value ) ) )
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order ^ floats value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ( .withOrder ^ ValueLayout$OfFloat float-layout byte-order ) ^ long offset ^ int ( alength value ) ) ) )
2024-10-04 14:17:27 +00:00
( defn write-doubles
" Writes a [ [ double ] ] array to the ` segment ` , at an optional ` offset ` .
If ` byte-order ` is not provided , it defaults to [ [ native-endian ] ] . "
{ :inline
( fn write-doubles-inline
( [ segment value ]
` ( let [ segment# ~ segment
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 ^ MemorySegment segment# ^ ValueLayout$OfDouble double-layout 0 ^ int ( alength value# ) )
2024-10-04 14:17:27 +00:00
) )
( [ segment offset value ]
` ( let [ segment# ~ segment
offset# ~ offset
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 ^ MemorySegment segment# ^ ValueLayout$OfDouble double-layout ^ long offset ^ int ( alength value# ) )
2024-10-04 14:17:27 +00:00
) )
( [ segment offset byte-order value ]
` ( let [ segment# ~ segment
offset# ~ offset
byte-order# ~ byte-order
value# ~ value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value# 0 ^ MemorySegment segment# ( .withOrder ^ ValueLayout$OfDouble double-layout ^ ByteOrder byte-order# ) ^ long offset ^ int ( alength value# ) ) ) ) ) }
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ doubles value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ^ ValueLayout$OfDouble double-layout 0 ^ int ( alength value ) ) )
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ long offset ^ doubles value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ^ ValueLayout$OfDouble double-layout ^ long offset ^ int ( alength value ) ) )
2024-10-04 14:17:27 +00:00
( [ ^ MemorySegment segment ^ long offset ^ ByteOrder byte-order ^ doubles value ]
2024-10-10 13:59:28 +00:00
( MemorySegment/copy value 0 segment ( .withOrder ^ ValueLayout$OfDouble double-layout byte-order ) ^ long offset ^ int ( alength value ) ) ) )
2024-10-04 14:17:27 +00:00
2021-09-26 19:11:29 +00:00
( defn- type-dispatch
"Gets a type dispatch value from a (potentially composite) type."
[ type ]
( cond
( qualified-keyword? type ) type
2022-01-18 20:00:00 +00:00
( sequential? type ) ( keyword ( first type ) )
:else ( throw ( ex-info "Invalid type object" { :type type } ) ) ) )
2021-09-26 19:11:29 +00:00
2022-01-18 20:00:13 +00:00
( def primitive-types
2021-10-13 14:57:23 +00:00
"A set of all primitive types."
2022-04-15 14:56:38 +00:00
# { ::byte ::short ::int ::long
2021-10-13 14:57:23 +00:00
::char ::float ::double ::pointer } )
2022-01-18 20:00:13 +00:00
( defn primitive?
"A predicate to determine if a given type is primitive."
[ type ]
( contains? primitive-types ( type-dispatch type ) ) )
2021-09-26 19:11:29 +00:00
( defmulti primitive-type
" Gets the primitive type that is used to pass as an argument for the ` type ` .
This is for objects which are passed to native functions as primitive types ,
but which need additional logic to be performed during serialization and
deserialization.
2021-10-13 18:51:13 +00:00
Implementations of this method should take into account that type arguments
may not always be evaluated before passing to this function.
2021-09-26 19:11:29 +00:00
Returns nil for any type which does not have a primitive representation. "
type-dispatch )
( defmethod primitive-type :default
2021-10-10 16:55:06 +00:00
[ _type ]
nil )
( defmethod primitive-type ::byte
[ _type ]
::byte )
( defmethod primitive-type ::short
[ _type ]
::short )
( defmethod primitive-type ::int
[ _type ]
::int )
( defmethod primitive-type ::long
[ _type ]
::long )
( defmethod primitive-type ::char
[ _type ]
::char )
( defmethod primitive-type ::float
[ _type ]
::float )
( defmethod primitive-type ::double
[ _type ]
::double )
2021-09-26 19:11:29 +00:00
( defmethod primitive-type ::pointer
[ _type ]
::pointer )
2021-10-10 16:55:06 +00:00
( defmethod primitive-type ::void
[ _type ]
::void )
2021-09-26 19:11:29 +00:00
( defmulti c-layout
" Gets the layout object for a given ` type ` .
If a type is primitive it will return the appropriate primitive
layout ( see [ [ c-prim-layout ] ] ) .
Otherwise , it should return a [ [ GroupLayout ] ] for the given type. "
type-dispatch )
( defmethod c-layout :default
[ type ]
2021-10-10 16:59:57 +00:00
( c-layout ( primitive-type type ) ) )
( defmethod c-layout ::byte
[ _type ]
2022-01-18 19:27:22 +00:00
byte-layout )
2021-10-10 16:59:57 +00:00
( defmethod c-layout ::short
2022-01-18 20:15:18 +00:00
[ type ]
( if ( sequential? type )
2022-04-15 14:56:38 +00:00
( .withOrder short-layout ^ ByteOrder ( second type ) )
2022-01-18 20:15:18 +00:00
short-layout ) )
2021-10-10 16:59:57 +00:00
( defmethod c-layout ::int
2022-01-18 20:15:18 +00:00
[ type ]
( if ( sequential? type )
2022-04-15 14:56:38 +00:00
( .withOrder int-layout ^ ByteOrder ( second type ) )
2022-01-18 20:15:18 +00:00
int-layout ) )
2021-10-10 16:59:57 +00:00
( defmethod c-layout ::long
2022-01-18 20:15:18 +00:00
[ type ]
( if ( sequential? type )
2022-04-15 14:56:38 +00:00
( .withOrder long-layout ^ ByteOrder ( second type ) )
2022-01-18 20:15:18 +00:00
long-layout ) )
2021-10-10 16:59:57 +00:00
( defmethod c-layout ::char
[ _type ]
2022-01-18 19:27:22 +00:00
char-layout )
2021-10-10 16:59:57 +00:00
( defmethod c-layout ::float
2022-01-18 20:15:18 +00:00
[ type ]
( if ( sequential? type )
2022-04-15 14:56:38 +00:00
( .withOrder float-layout ^ ByteOrder ( second type ) )
2022-01-18 20:15:18 +00:00
float-layout ) )
2021-10-10 16:59:57 +00:00
( defmethod c-layout ::double
2022-01-18 20:15:18 +00:00
[ type ]
( if ( sequential? type )
2022-04-15 14:56:38 +00:00
( .withOrder double-layout ^ ByteOrder ( second type ) )
2022-01-18 20:15:18 +00:00
double-layout ) )
2021-10-10 16:59:57 +00:00
( defmethod c-layout ::pointer
[ _type ]
2022-01-18 19:27:22 +00:00
pointer-layout )
2021-09-26 19:11:29 +00:00
( def java-prim-layout
"Map of primitive type names to the Java types for a method handle."
{ ::byte Byte/TYPE
::short Short/TYPE
::int Integer/TYPE
::long Long/TYPE
::char Byte/TYPE
::float Float/TYPE
::double Double/TYPE
2024-01-29 12:22:39 +00:00
::pointer MemorySegment
2021-09-26 19:11:29 +00:00
::void Void/TYPE } )
( defn java-layout
" Gets the Java class to an argument of this type for a method handle.
If a type serializes to a primitive it returns return a Java primitive type.
Otherwise , it returns [ [ MemorySegment ] ] . "
2022-01-18 19:28:00 +00:00
^ Class [ type ]
2021-09-26 19:11:29 +00:00
( java-prim-layout ( or ( primitive-type type ) type ) MemorySegment ) )
( defn size-of
"The size in bytes of the given `type`."
2022-01-18 19:28:00 +00:00
^ long [ type ]
( let [ t ( cond-> type
( not ( instance? MemoryLayout type ) ) c-layout ) ]
( .byteSize ^ MemoryLayout t ) ) )
2021-09-26 19:11:29 +00:00
2022-01-10 19:30:01 +00:00
( defn align-of
"The alignment in bytes of the given `type`."
2022-01-18 19:28:00 +00:00
^ long [ type ]
( let [ t ( cond-> type
( not ( instance? MemoryLayout type ) ) c-layout ) ]
( .byteAlignment ^ MemoryLayout t ) ) )
2022-01-10 19:30:01 +00:00
2021-09-26 19:11:29 +00:00
( defn alloc-instance
"Allocates a memory segment for the given `type`."
2024-01-29 12:22:39 +00:00
( ^ MemorySegment [ type ] ( alloc-instance type ( auto-arena ) ) )
( ^ MemorySegment [ type arena ] ( .allocate ^ Arena arena ^ long ( size-of type ) ^ long ( align-of type ) ) ) )
2021-09-26 19:11:29 +00:00
( declare serialize serialize-into )
( defmulti serialize*
" Constructs a serialized version of the ` obj ` and returns it.
Any new allocations made during the serialization should be tied to the given
2024-09-30 16:17:04 +00:00
` arena ` , except in extenuating circumstances.
2021-09-26 19:11:29 +00:00
This method should only be implemented for types that serialize to primitives. "
( fn
# _ { :clj-kondo/ignore [ :unused-binding ] }
2024-09-30 16:17:04 +00:00
[ obj type arena ]
2021-09-26 19:11:29 +00:00
( type-dispatch type ) ) )
( defmethod serialize* :default
2024-09-30 16:17:04 +00:00
[ obj type _arena ]
2021-10-10 17:05:19 +00:00
( throw ( ex-info "Attempted to serialize a non-primitive type with primitive methods"
{ :type type
:object obj } ) ) )
( defmethod serialize* ::byte
2024-09-30 16:17:04 +00:00
[ obj _type _arena ]
2021-10-10 17:05:19 +00:00
( byte obj ) )
( defmethod serialize* ::short
2024-09-30 16:17:04 +00:00
[ obj _type _arena ]
2021-10-10 17:05:19 +00:00
( short obj ) )
( defmethod serialize* ::int
2024-09-30 16:17:04 +00:00
[ obj _type _arena ]
2021-10-10 17:05:19 +00:00
( int obj ) )
( defmethod serialize* ::long
2024-09-30 16:17:04 +00:00
[ obj _type _arena ]
2021-10-10 17:05:19 +00:00
( long obj ) )
( defmethod serialize* ::char
2024-09-30 16:17:04 +00:00
[ obj _type _arena ]
2021-10-10 17:05:19 +00:00
( char obj ) )
( defmethod serialize* ::float
2024-09-30 16:17:04 +00:00
[ obj _type _arena ]
2021-10-10 17:05:19 +00:00
( float obj ) )
( defmethod serialize* ::double
2024-09-30 16:17:04 +00:00
[ obj _type _arena ]
2021-10-10 17:05:19 +00:00
( double obj ) )
2021-09-26 19:11:29 +00:00
( defmethod serialize* ::pointer
2024-09-30 16:17:04 +00:00
[ obj type arena ]
2021-10-01 17:03:25 +00:00
( if-not ( null? obj )
2021-09-26 19:11:29 +00:00
( if ( sequential? type )
2024-09-30 16:17:04 +00:00
( let [ segment ( alloc-instance ( second type ) arena ) ]
( serialize-into obj ( second type ) segment arena )
2024-01-29 12:22:39 +00:00
( address-of segment ) )
2021-10-01 17:03:25 +00:00
obj )
2024-10-02 20:22:29 +00:00
null ) )
2021-09-26 19:11:29 +00:00
2021-10-15 00:22:30 +00:00
( defmethod serialize* ::void
2024-09-30 16:17:04 +00:00
[ _obj _type _arena ]
2021-10-15 00:22:30 +00:00
nil )
2021-09-26 19:11:29 +00:00
( defmulti serialize-into
" Writes a serialized version of the ` obj ` to the given ` segment ` .
Any new allocations made during the serialization should be tied to the given
2024-09-30 16:17:04 +00:00
` arena ` , except in extenuating circumstances.
2021-09-26 19:11:29 +00:00
This method should be implemented for any type which does not
override [ [ c-layout ] ] .
For any other type , this will serialize it as [ [ serialize* ] ] before writing
2024-01-29 12:22:39 +00:00
the result value into the ` segment ` . "
2021-09-26 19:11:29 +00:00
( fn
# _ { :clj-kondo/ignore [ :unused-binding ] }
2024-09-30 16:17:04 +00:00
[ obj type segment arena ]
2021-09-26 19:11:29 +00:00
( type-dispatch type ) ) )
( defmethod serialize-into :default
2024-09-30 16:17:04 +00:00
[ obj type segment arena ]
2021-09-26 19:11:29 +00:00
( if-some [ prim-layout ( primitive-type type ) ]
2024-09-30 16:17:04 +00:00
( serialize-into ( serialize* obj type arena ) prim-layout segment arena )
2022-11-16 15:27:01 +00:00
( throw ( ex-info "Attempted to serialize an object to a type that has not been overridden"
2021-09-26 19:11:29 +00:00
{ :type type
:object obj } ) ) ) )
( defmethod serialize-into ::byte
2024-09-30 16:17:04 +00:00
[ obj _type segment _arena ]
2022-01-18 19:48:44 +00:00
( write-byte segment ( byte obj ) ) )
2021-09-26 19:11:29 +00:00
( defmethod serialize-into ::short
2024-09-30 16:17:04 +00:00
[ obj type segment _arena ]
2022-01-18 19:48:44 +00:00
( if ( sequential? type )
( write-short segment 0 ( second type ) ( short obj ) )
( write-short segment ( short obj ) ) ) )
2021-09-26 19:11:29 +00:00
( defmethod serialize-into ::int
2024-09-30 16:17:04 +00:00
[ obj type segment _arena ]
2022-01-18 19:48:44 +00:00
( if ( sequential? type )
( write-int segment 0 ( second type ) ( int obj ) )
( write-int segment ( int obj ) ) ) )
2021-09-26 19:11:29 +00:00
( defmethod serialize-into ::long
2024-09-30 16:17:04 +00:00
[ obj type segment _arena ]
2022-01-18 19:48:44 +00:00
( if ( sequential? type )
( write-long segment 0 ( second type ) ( long obj ) )
( write-long segment ( long obj ) ) ) )
2021-09-26 19:11:29 +00:00
( defmethod serialize-into ::char
2024-09-30 16:17:04 +00:00
[ obj _type segment _arena ]
2022-01-18 19:48:44 +00:00
( write-char segment ( char obj ) ) )
2021-09-26 19:11:29 +00:00
( defmethod serialize-into ::float
2024-09-30 16:17:04 +00:00
[ obj type segment _arena ]
2022-01-18 19:48:44 +00:00
( if ( sequential? type )
( write-float segment 0 ( second type ) ( float obj ) )
( write-float segment ( float obj ) ) ) )
2021-09-26 19:11:29 +00:00
( defmethod serialize-into ::double
2024-09-30 16:17:04 +00:00
[ obj type segment _arena ]
2022-01-18 19:48:44 +00:00
( if ( sequential? type )
( write-double segment 0 ( second type ) ( double obj ) )
( write-double segment ( double obj ) ) ) )
2021-09-26 19:11:29 +00:00
( defmethod serialize-into ::pointer
2024-09-30 16:17:04 +00:00
[ obj type segment arena ]
2024-01-29 12:22:39 +00:00
( write-address
segment
( cond-> obj
2024-09-30 16:17:04 +00:00
( sequential? type ) ( serialize* type arena ) ) ) )
2021-09-26 19:11:29 +00:00
( defn serialize
" Serializes an arbitrary type.
For types which have a primitive representation , this serializes into that
representation. For types which do not , it allocates a new segment and
serializes into that. "
2024-09-30 16:17:04 +00:00
( [ obj type ] ( serialize obj type ( auto-arena ) ) )
( [ obj type arena ]
2021-09-26 19:11:29 +00:00
( if ( primitive-type type )
2024-09-30 16:17:04 +00:00
( serialize* obj type arena )
( let [ segment ( alloc-instance type arena ) ]
( serialize-into obj type segment arena )
2021-09-26 19:11:29 +00:00
segment ) ) ) )
( declare deserialize deserialize* )
( defmulti deserialize-from
" Deserializes the given segment into a Clojure data structure.
For types that serialize to primitives , a default implementation will
2024-01-29 12:22:39 +00:00
deserialize the primitive before calling [ [ deserialize* ] ] . "
2021-09-26 19:11:29 +00:00
( fn
# _ { :clj-kondo/ignore [ :unused-binding ] }
[ segment type ]
( type-dispatch type ) ) )
( defmethod deserialize-from :default
[ segment type ]
( if-some [ prim ( primitive-type type ) ]
2021-10-10 17:11:14 +00:00
( -> segment
( deserialize-from prim )
( deserialize* type ) )
2021-09-26 19:11:29 +00:00
( throw ( ex-info "Attempted to deserialize a non-primitive type that has not been overriden"
{ :type type
:segment segment } ) ) ) )
( defmethod deserialize-from ::byte
[ segment _type ]
2022-01-18 19:48:44 +00:00
( read-byte segment ) )
2021-09-26 19:11:29 +00:00
( defmethod deserialize-from ::short
2022-01-18 19:48:44 +00:00
[ segment type ]
( if ( sequential? type )
( read-short segment 0 ( second type ) )
( read-short segment ) ) )
2021-09-26 19:11:29 +00:00
( defmethod deserialize-from ::int
2022-01-18 19:48:44 +00:00
[ segment type ]
( if ( sequential? type )
( read-int segment 0 ( second type ) )
( read-int segment ) ) )
2021-09-26 19:11:29 +00:00
( defmethod deserialize-from ::long
2022-01-18 19:48:44 +00:00
[ segment type ]
( if ( sequential? type )
( read-long segment 0 ( second type ) )
( read-long segment ) ) )
2021-09-26 19:11:29 +00:00
( defmethod deserialize-from ::char
[ segment _type ]
2022-01-18 19:48:44 +00:00
( read-char segment ) )
2021-09-26 19:11:29 +00:00
( defmethod deserialize-from ::float
2022-01-18 19:48:44 +00:00
[ segment type ]
( if ( sequential? type )
( read-float segment 0 ( second type ) )
( read-float segment ) ) )
2021-09-26 19:11:29 +00:00
( defmethod deserialize-from ::double
2022-01-18 19:48:44 +00:00
[ segment type ]
( if ( sequential? type )
( read-double segment 0 ( second type ) )
( read-double segment ) ) )
2021-09-26 19:11:29 +00:00
( defmethod deserialize-from ::pointer
[ segment type ]
2024-01-29 12:22:39 +00:00
( cond-> ( read-address segment )
( sequential? type ) ( deserialize* type ) ) )
2021-09-26 19:11:29 +00:00
( defmulti deserialize*
" Deserializes a primitive object into a Clojure data structure.
This is intended for use with types that are returned as a primitive but which
need additional processing before they can be returned. "
( fn
# _ { :clj-kondo/ignore [ :unused-binding ] }
[ obj type ]
( type-dispatch type ) ) )
( defmethod deserialize* :default
[ obj type ]
2021-10-10 17:11:26 +00:00
( throw ( ex-info "Attempted to deserialize a non-primitive type with primitive methods"
{ :type type
:segment obj } ) ) )
( defmethod deserialize* ::byte
[ obj _type ]
obj )
( defmethod deserialize* ::short
[ obj _type ]
obj )
( defmethod deserialize* ::int
[ obj _type ]
obj )
( defmethod deserialize* ::long
[ obj _type ]
obj )
( defmethod deserialize* ::char
[ obj _type ]
obj )
( defmethod deserialize* ::float
[ obj _type ]
obj )
( defmethod deserialize* ::double
[ obj _type ]
obj )
2021-09-26 19:11:29 +00:00
( defmethod deserialize* ::pointer
[ addr type ]
( when-not ( null? addr )
( if ( sequential? type )
2024-01-29 12:22:39 +00:00
( let [ target-type ( second type ) ]
( deserialize-from
( .reinterpret ^ MemorySegment ( read-address addr )
^ long ( size-of target-type ) )
target-type ) )
2021-09-26 19:11:29 +00:00
addr ) ) )
2021-10-10 17:11:26 +00:00
( defmethod deserialize* ::void
[ _obj _type ]
nil )
2021-09-26 19:11:29 +00:00
( defn deserialize
" Deserializes an arbitrary type.
For types which have a primitive representation , this deserializes the
primitive representation. For types which do not , this deserializes out of
a segment. "
[ obj type ]
( when-not ( identical? ::void type )
2021-09-27 17:09:23 +00:00
( if ( primitive-type type )
( deserialize* obj type )
( deserialize-from obj type ) ) ) )
2021-09-26 19:11:29 +00:00
( defn seq-of
"Constructs a lazy sequence of `type` elements deserialized from `segment`."
[ type segment ]
2024-01-29 12:22:39 +00:00
( map # ( deserialize % type ) ( slice-segments segment ( size-of type ) ) ) )
2021-09-26 19:11:29 +00:00
2022-07-17 00:37:46 +00:00
;;; Raw composite types
2022-07-17 00:46:45 +00:00
;; TODO(Joshua): Ensure that all the raw values don't have anything happen on
;; serialize in the inlining of [[coffi.ffi/make-serde-wrapper]]
2022-07-17 00:37:46 +00:00
( defmethod c-layout ::raw
[ [ _raw type ] ]
( c-layout type ) )
( defmethod serialize-into ::raw
2024-09-30 16:17:04 +00:00
[ obj _type segment _arena ]
2022-11-30 03:31:28 +00:00
( if ( instance? MemorySegment obj )
( copy-segment segment obj )
obj ) )
2022-07-17 00:37:46 +00:00
( defmethod deserialize-from ::raw
[ segment _type ]
2022-11-30 03:31:28 +00:00
( if ( instance? MemorySegment segment )
( clone-segment segment )
segment ) )
2022-07-17 00:37:46 +00:00
2021-09-26 19:11:29 +00:00
;;; C String type
( defmethod primitive-type ::c-string
[ _type ]
::pointer )
( defmethod serialize* ::c-string
2024-09-30 16:17:04 +00:00
[ obj _type ^ Arena arena ]
2021-09-26 19:11:29 +00:00
( if obj
2024-09-30 16:17:04 +00:00
( .allocateFrom arena ^ String obj )
2024-10-02 20:22:29 +00:00
null ) )
2021-09-26 19:11:29 +00:00
( defmethod deserialize* ::c-string
[ addr _type ]
( when-not ( null? addr )
2024-06-12 18:10:52 +00:00
( .getString ( .reinterpret ^ MemorySegment addr Integer/MAX_VALUE ) 0 ) ) )
2021-09-26 19:11:29 +00:00
;;; Union types
( defmethod c-layout ::union
[ [ _union types & { :as _opts } :as _type ] ]
( let [ items ( map c-layout types ) ]
( MemoryLayout/unionLayout
( into-array MemoryLayout items ) ) ) )
( defmethod serialize-into ::union
2024-09-30 16:17:04 +00:00
[ obj [ _union _types & { :keys [ dispatch extract ] } :as type ] segment arena ]
2021-09-26 19:11:29 +00:00
( when-not dispatch
( throw ( ex-info "Attempted to serialize a union with no dispatch function"
{ :type type
:value obj } ) ) )
( let [ type ( dispatch obj ) ]
( serialize-into
( if extract
( extract type obj )
obj )
type
segment
2024-09-30 16:17:04 +00:00
arena ) ) )
2021-09-26 19:11:29 +00:00
( defmethod deserialize-from ::union
[ segment type ]
( clone-segment ( slice segment 0 ( size-of type ) ) ) )
;;; Struct types
( defmethod c-layout ::struct
[ [ _struct fields ] ]
( let [ fields ( for [ [ field-name field ] fields ]
( .withName ^ MemoryLayout ( c-layout field )
( name field-name ) ) ) ]
( MemoryLayout/structLayout
( into-array MemoryLayout fields ) ) ) )
( defmethod serialize-into ::struct
2024-09-30 16:17:04 +00:00
[ obj [ _struct fields ] segment arena ]
2021-09-26 19:11:29 +00:00
( loop [ offset 0
fields fields ]
( when ( seq fields )
( let [ [ field type ] ( first fields )
size ( size-of type ) ]
( serialize-into
( get obj field ) type
2024-09-30 16:17:04 +00:00
( slice segment offset size ) arena )
2021-09-26 19:11:29 +00:00
( recur ( long ( + offset size ) ) ( rest fields ) ) ) ) ) )
( defmethod deserialize-from ::struct
[ segment [ _struct fields ] ]
( loop [ offset 0
fields fields
obj { } ]
( if ( seq fields )
( let [ [ field type ] ( first fields )
size ( size-of type ) ]
( recur
( long ( + offset size ) )
( rest fields )
( assoc obj field ( deserialize-from
( slice segment offset size )
type ) ) ) )
obj ) ) )
;;; Padding type
( defmethod c-layout ::padding
[ [ _padding size ] ]
2024-01-29 12:22:39 +00:00
( MemoryLayout/paddingLayout size ) )
2021-09-26 19:11:29 +00:00
( defmethod serialize-into ::padding
2024-09-30 16:17:04 +00:00
[ _obj [ _padding _size ] _segment _arena ]
2021-09-26 19:11:29 +00:00
nil )
( defmethod deserialize-from ::padding
[ _segment [ _padding _size ] ]
nil )
;;; Array types
( defmethod c-layout ::array
[ [ _array type count ] ]
( MemoryLayout/sequenceLayout
count
( c-layout type ) ) )
( defmethod serialize-into ::array
2024-09-30 16:17:04 +00:00
[ obj [ _array type count ] segment arena ]
2021-09-26 19:11:29 +00:00
( dorun
2024-09-30 16:17:04 +00:00
( map # ( serialize-into %1 type %2 arena )
2021-09-26 19:11:29 +00:00
obj
( slice-segments ( slice segment 0 ( * count ( size-of type ) ) )
( size-of type ) ) ) ) )
( defmethod deserialize-from ::array
[ segment [ _array type count ] ]
2021-10-09 00:26:46 +00:00
( mapv # ( deserialize-from % type )
( slice-segments ( slice segment 0 ( * count ( size-of type ) ) )
( size-of type ) ) ) )
2021-09-26 19:11:29 +00:00
2022-07-07 19:15:33 +00:00
;;; Enum types
( defmethod primitive-type ::enum
[ [ _enum _variants & { :keys [ repr ] } ] ]
( if repr
( primitive-type repr )
::int ) )
( defn- enum-variants-map
" Constructs a map from enum variant objects to their native representations.
Enums are mappings from Clojure objects to numbers , with potential default
values for each element based on order.
If ` variants ` is a map , then every variant has a value provided already ( a
guarantee of maps in Clojure 's syntax ) and we are done.
If ` variants ` is a vector then we assume C-style implicit enum values ,
counting from 0 . If an element of ` variants ` itself is a vector , it must be a
vector tuple of the variant object to the native representation , with further
counting continuing from that value. "
[ variants ]
( if ( map? variants )
variants
2022-07-07 20:23:52 +00:00
( first
( reduce
( fn [ [ m next-id ] variant ]
( if ( vector? variant )
[ ( conj m variant ) ( inc ( second variant ) ) ]
[ ( assoc m variant next-id ) ( inc next-id ) ] ) )
[ { } 0 ]
variants ) ) ) )
2022-07-07 19:15:33 +00:00
( defmethod serialize* ::enum
2024-09-30 16:17:04 +00:00
[ obj [ _enum variants & { :keys [ repr ] } ] arena ]
2022-07-07 19:15:33 +00:00
( serialize* ( ( enum-variants-map variants ) obj )
( or repr ::int )
2024-09-30 16:17:04 +00:00
arena ) )
2022-07-07 19:15:33 +00:00
( defmethod deserialize* ::enum
[ obj [ _enum variants & { :keys [ _repr ] } ] ]
( ( set/map-invert ( enum-variants-map variants ) ) obj ) )
2022-07-07 21:08:41 +00:00
;;; Flagsets
( defmethod primitive-type ::flagset
[ [ _flagset _bits & { :keys [ repr ] } ] ]
( if repr
( primitive-type repr )
::int ) )
( defmethod serialize* ::flagset
2024-09-30 16:17:04 +00:00
[ obj [ _flagset bits & { :keys [ repr ] } ] arena ]
2022-07-07 21:08:41 +00:00
( let [ bits-map ( enum-variants-map bits ) ]
2024-09-30 16:17:04 +00:00
( reduce # ( bit-set %1 ( get bits-map %2 ) ) ( serialize* 0 ( or repr ::int ) arena ) obj ) ) )
2022-07-07 21:08:41 +00:00
( defmethod deserialize* ::flagset
[ obj [ _flagset bits & { :keys [ repr ] } ] ]
( let [ bits-map ( set/map-invert ( enum-variants-map bits ) ) ]
( reduce # ( if-not ( zero? ( bit-and 1 ( bit-shift-right obj %2 ) ) )
( conj %1 ( bits-map %2 ) )
%1 )
# { }
( range ( * 8 ( size-of ( or repr ::int ) ) ) ) ) ) )
2021-09-26 19:11:29 +00:00
( s/def ::type
( s/spec
( s/nonconforming
( s/or :simple-type qualified-keyword?
:complex-type ( s/cat :base-type qualified-keyword?
:type-args ( s/* any? ) ) ) ) ) )
( defmacro defalias
" Defines a type alias from ` new-type ` to ` aliased-type ` .
This creates needed serialization and deserialization implementations for the
aliased type. "
{ :style/indent [ :defn ] }
[ new-type aliased-type ]
2022-01-10 19:34:58 +00:00
( if ( and ( s/valid? ::type aliased-type )
( primitive-type aliased-type ) )
2021-09-26 19:11:29 +00:00
` ( let [ aliased# ~ aliased-type ]
( defmethod primitive-type ~ new-type
[ _type# ]
( primitive-type aliased# ) )
( defmethod serialize* ~ new-type
2024-09-30 16:17:04 +00:00
[ obj# _type# arena# ]
( serialize* obj# aliased# arena# ) )
2021-09-26 19:11:29 +00:00
( defmethod deserialize* ~ new-type
[ obj# _type# ]
( deserialize* obj# aliased# ) ) )
` ( let [ aliased# ~ aliased-type ]
( defmethod c-layout ~ new-type
[ _type# ]
( c-layout aliased# ) )
( defmethod serialize-into ~ new-type
2024-09-30 16:17:04 +00:00
[ obj# _type# segment# arena# ]
( serialize-into obj# aliased# segment# arena# ) )
2021-09-26 19:11:29 +00:00
( defmethod deserialize-from ~ new-type
[ segment# _type# ]
( deserialize-from segment# aliased# ) ) ) ) )
( s/fdef defalias
:args ( s/cat :new-type qualified-keyword?
2022-01-10 19:34:58 +00:00
:aliased-type any? ) )
2024-10-10 13:59:28 +00:00
2024-10-11 12:53:09 +00:00
( defn- with-c-layout
" Forces a struct specification to C layout rules.
This will add padding fields between fields to match C alignment
requirements. "
[ struct-spec ]
( let [ aligned-fields
( loop [ offset 0
aligned-fields [ ]
fields ( nth struct-spec 1 ) ]
( if ( seq fields )
( let [ [ [ _ type :as field ] & fields ] fields
2024-10-11 13:17:54 +00:00
size ( size-of type )
align ( align-of type )
2024-10-11 12:53:09 +00:00
r ( rem offset align ) ]
( recur ( cond-> ( + offset size )
( pos? r ) ( + ( - align r ) ) )
( cond-> aligned-fields
2024-10-11 13:17:54 +00:00
( pos? r ) ( conj [ ::padding [ ::padding ( - align r ) ] ] )
2024-10-11 12:53:09 +00:00
:always ( conj field ) )
fields ) )
2024-10-11 13:17:54 +00:00
( let [ strongest-alignment ( reduce max ( map ( comp align-of second ) ( nth struct-spec 1 ) ) )
2024-10-11 12:53:09 +00:00
r ( rem offset strongest-alignment ) ]
( cond-> aligned-fields
2024-10-11 13:17:54 +00:00
( pos? r ) ( conj [ ::padding [ ::padding ( - strongest-alignment r ) ] ] ) ) ) ) ) ]
2024-10-11 12:53:09 +00:00
( assoc struct-spec 1 aligned-fields ) ) )
2024-10-11 13:52:40 +00:00
( defmacro with-typehint [ bindings form ]
( let [ bindmap ( ->>
bindings
( partition 2 2 )
( map ( fn [ [ sym hint ] ] [ sym ( with-meta sym { :tag hint } ) ] ) )
( into ( hash-map ) ) ) ]
( clojure.walk/postwalk
( fn [ x ] ( get bindmap x x ) )
form ) ) )
2024-10-11 12:25:18 +00:00
( defn- typename->coffi-typename [ _type ]
( get
{ 'byte ::byte
'short ::short
'int ::int
'long ::long
'char ::char
'float ::float
'double ::double
'bytes [ ::array ::byte ]
'shorts [ ::array ::byte ]
'ints [ ::array ::byte ]
'longs [ ::array ::byte ]
'chars ::c-string
'floats [ ::array ::byte ]
'doubles [ ::array ::byte ] }
_type
_type ) )
2024-10-11 13:52:40 +00:00
( defn coffitype->array-fn [ _type ]
( get
{ :coffi.mem/byte ` byte-array
:coffi.mem/short ` short-array
:coffi.mem/int ` int-array
:coffi.mem/long ` long-array
:coffi.mem/char ` char-array
:coffi.mem/float ` float-array
:coffi.mem/double ` double-array }
_type
` object-array ) )
( defmulti generate-deserialize ( fn [ & xs ] ( if ( vector? ( first xs ) ) ( first ( first xs ) ) ( first xs ) ) ) )
( defmethod generate-deserialize :coffi.mem/byte [ _type offset ] [ ` ( read-byte ~ 'segment ~ offset ) ] )
( defmethod generate-deserialize :coffi.mem/short [ _type offset ] [ ` ( read-short ~ 'segment ~ offset ) ] )
( defmethod generate-deserialize :coffi.mem/int [ _type offset ] [ ` ( read-int ~ 'segment ~ offset ) ] )
( defmethod generate-deserialize :coffi.mem/long [ _type offset ] [ ` ( read-long ~ 'segment ~ offset ) ] )
( defmethod generate-deserialize :coffi.mem/char [ _type offset ] [ ` ( read-char ~ 'segment ~ offset ) ] )
( defmethod generate-deserialize :coffi.mem/float [ _type offset ] [ ` ( read-float ~ 'segment ~ offset ) ] )
( defmethod generate-deserialize :coffi.mem/double [ _type offset ] [ ` ( read-double ~ 'segment ~ offset ) ] )
( defmethod generate-deserialize :coffi.mem/pointer [ _type offset ] [ ` ( read-address ~ 'segment ~ offset ) ] )
( defmethod generate-deserialize :coffi.mem/c-string [ _type offset ] [ ` ( list with-typehint [ 'addr java.lang.foreign.MemorySegment ] ( list ` .getString ( list ` .reinterpret 'addr ` Integer/MAX_VALUE ) 0 ) ) ] )
( defmethod generate-deserialize :coffi.mem/array [ _type offset ]
( let [ outer-code ` ( let [ arr# ( ~ ( coffitype->array-fn ( second _type ) ) ~ ( second ( rest _type ) ) ) ] arr# )
gen-arr ( nth outer-code 2 ) ]
[ ( concat ( butlast outer-code )
[ ` aset gen-arr ]
( reduce
concat
( map
( fn [ index ]
( let [ deserialize-instructions
( generate-deserialize
( second _type )
( + offset ( * ( size-of ( second _type ) ) index ) ) ) ]
( if ( vector? deserialize-instructions )
( list index ( first deserialize-instructions ) )
( list index deserialize-instructions ) ) ) )
( range ( second ( rest _type ) ) ) ) )
[ gen-arr ] ) ] ) )
( defn register-new-struct-deserialization [ typename [ _struct fields ] ]
( let [ typelist ( ->>
( partition 2 2 ( interleave ( reductions + 0 ( map ( comp size-of second ) fields ) ) fields ) )
( filter ( fn [ [ _ [ _ field-type ] ] ] ( not ( and ( vector? field-type ) ( = ::padding ( first field-type ) ) ) ) ) ) ) ]
( defmethod generate-deserialize typename [ _type global-offset ]
( ->> typelist
( map-indexed
( fn [ index [ offset [ _ field-type ] ] ]
( generate-deserialize field-type ( + global-offset offset ) ) ) )
( reduce concat )
( cons ( symbol ( str ( name typename ) "." ) ) )
) ) ) )
2024-10-11 12:25:18 +00:00
( defmacro defstruct
" Defines a struct type. all members need a type hint.
This creates needed serialization and deserialization implementations for the
aliased type. "
{ :style/indent [ :defn ] }
[ typename members ]
( cond
( odd? ( count members ) ) ( throw ( Exception. "uneven amount of members supplied. members have to be typed and are required to be supplied in the form of `type member-name` (not via metadata on the symbols)" ) )
:else
2024-10-11 13:52:40 +00:00
( let [ coffi-typename ( keyword ( str *ns* ) ( str typename ) )
typed-symbols ( ->>
2024-10-11 12:25:18 +00:00
members
( partition 2 2 )
( map ( fn [ [ hint sym ] ] ( with-meta sym { :tag hint } ) ) )
( vec ) )
2024-10-11 13:18:35 +00:00
struct-layout ( with-c-layout [ ::struct
( ->>
members
( partition 2 2 )
( map vec )
( map # ( update % 0 typename->coffi-typename ) )
( map # ( update % 1 keyword ) )
( map reverse )
( map vec ) ) ] ) ]
2024-10-11 13:52:40 +00:00
( register-new-struct-deserialization coffi-typename struct-layout )
2024-10-11 12:25:18 +00:00
` ( do
( defrecord ~ typename ~ typed-symbols )
2024-10-11 13:52:40 +00:00
( defmethod c-layout ~ coffi-typename [ ~ '_ ] ~ struct-layout )
( defmethod deserialize-from ~ coffi-typename ~ [ 'segment '_type ]
~ ( generate-deserialize coffi-typename 0 ) )
2024-10-11 12:25:18 +00:00
)
)
)
)
2024-10-10 13:59:28 +00:00