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 ]
2024-10-11 22:36:21 +00:00
'shorts [ ::array ::short ]
'ints [ ::array ::int ]
'longs [ ::array ::long ]
2024-10-11 12:25:18 +00:00
'chars ::c-string
2024-10-11 22:36:21 +00:00
'floats [ ::array ::float ]
'doubles [ ::array ::double ] }
2024-10-11 12:25:18 +00:00
_type
2024-10-11 20:26:41 +00:00
( keyword ( str *ns* ) ( str _type ) ) ) )
2024-10-11 12:25:18 +00:00
2024-10-11 22:36:21 +00:00
( defn- coffitype->typename [ _type ]
( cond
( and ( vector? _type ) ( = ::array ( first _type ) ) ) ( get { ::byte 'bytes
::short 'shorts
::int 'ints
::long 'longs
::char 'chars
::float 'floats
::double 'doubles }
( second _type ) 'objects )
:default ( get { ::byte 'byte
::short 'short
::int 'int
::long 'long
::char 'char
::float 'float
::double 'double
::c-string 'String }
_type ( keyword ( str *ns* ) ( str _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 )
2024-10-11 22:36:21 +00:00
( list
( concat [ ` 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 ) ) ) ) ) ) )
2024-10-11 13:52:40 +00:00
[ gen-arr ] ) ] ) )
2024-10-11 15:48:58 +00:00
( defn typelist [ typename fields ]
( ->>
( 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 ) ) ) ) ) ) ) )
2024-10-11 13:52:40 +00:00
( defn register-new-struct-deserialization [ typename [ _struct fields ] ]
2024-10-11 15:48:58 +00:00
( let [ typelist ( typelist typename fields ) ]
2024-10-11 13:52:40 +00:00
( 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 20:26:41 +00:00
( list )
2024-10-11 13:52:40 +00:00
) ) ) )
2024-10-11 14:55:03 +00:00
( defmulti generate-serialize ( fn [ & xs ] ( if ( vector? ( first xs ) ) ( first ( first xs ) ) ( first xs ) ) ) )
( defmethod generate-serialize :coffi.mem/byte [ _type source-form offset ] ` ( write-byte ~ 'segment ~ offset ~ source-form ) )
( defmethod generate-serialize :coffi.mem/short [ _type source-form offset ] ` ( write-short ~ 'segment ~ offset ~ source-form ) )
( defmethod generate-serialize :coffi.mem/int [ _type source-form offset ] ` ( write-int ~ 'segment ~ offset ~ source-form ) )
( defmethod generate-serialize :coffi.mem/long [ _type source-form offset ] ` ( write-long ~ 'segment ~ offset ~ source-form ) )
( defmethod generate-serialize :coffi.mem/char [ _type source-form offset ] ` ( write-char ~ 'segment ~ offset ~ source-form ) )
( defmethod generate-serialize :coffi.mem/float [ _type source-form offset ] ` ( write-float ~ 'segment ~ offset ~ source-form ) )
( defmethod generate-serialize :coffi.mem/double [ _type source-form offset ] ` ( write-double ~ 'segment ~ offset ~ source-form ) )
( defmethod generate-serialize :coffi.mem/pointer [ _type source-form offset ] ` ( write-pointer ~ 'segment ~ offset ~ source-form ) )
( defmethod generate-serialize :coffi.mem/array [ [ _arr member-type length ] source-form offset ]
( concat
( list ` let [ 'array-obj source-form ] )
( map
( fn [ index ]
( generate-serialize member-type
( list ` aget 'array-obj index )
( + offset ( * ( size-of member-type ) index ) ) ) )
( range length ) ) ) )
2024-10-11 15:48:58 +00:00
( defn register-new-struct-serialization [ typename [ _struct fields ] ]
( let [ typelist ( typelist typename fields )
fieldnames ( filter # ( not= ::padding % ) ( map first fields ) ) ]
( defmethod generate-serialize typename [ _type source-form global-offset ]
( ->> typelist
( map-indexed
( fn [ index [ offset [ _ field-type ] ] ]
2024-10-11 20:26:41 +00:00
( generate-serialize field-type ( list ( symbol ( str "." ( name ( nth fieldnames index ) ) ) ) 'source-obj ) ( + global-offset offset ) ) ) )
( concat [ ` let [ 'source-obj source-form ] ] )
) ) ) )
2024-10-11 15:48:58 +00:00
2024-10-19 01:26:45 +00:00
( deftype struct-iterator [ ^ clojure.lang.IPersistentVector struct-type ^ int size ^ { :unsynchronized-mutable true :tag int } i ]
java.util.Iterator
( forEachRemaining [ action ] )
)
( gen-interface
:name coffi.mem.IStructImpl :methods
[ [ vec_length [ ] int ]
[ vec_assocN [ int Object ] clojure.lang.IPersistentVector ]
[ vec_peek [ ] Object ]
[ vec_pop [ ] clojure.lang.IPersistentVector ]
[ vec_nth [ int ] Object ]
[ vec_nth [ int Object ] Object ]
[ vec_cons [ Object ] clojure.lang.IPersistentCollection ]
[ vec_equiv [ Object ] boolean ]
[ vec_empty [ ] clojure.lang.IPersistentVector ]
[ vec_iterator [ ] java.util.Iterator ]
[ vec_forEach [ java.util.function.Consumer ] void ]
[ vec_seq [ ] clojure.lang.ISeq ]
[ vec_rseq [ ] clojure.lang.ISeq ]
[ struct_count [ ] int ]
[ struct_assoc [ Object Object ] clojure.lang.Associative ]
[ struct_containsKey [ Object ] boolean ]
[ struct_valAt [ Object ] Object ]
[ struct_valAt [ Object Object ] Object ]
[ struct_entryAt [ Object ] clojure.lang.IMapEntry ]
[ map_assocEx [ Object Object ] clojure.lang.IPersistentMap ]
[ map_without [ Object ] clojure.lang.IPersistentMap ]
[ map_cons [ Object ] clojure.lang.IPersistentCollection ]
[ map_equiv [ Object ] boolean ]
[ map_empty [ ] clojure.lang.IPersistentMap ]
[ map_iterator [ ] java.util.Iterator ]
[ map_forEach [ java.util.function.Consumer ] void ]
[ map_seq [ ] clojure.lang.ISeq ] ] )
( gen-interface :name coffi.mem.IStruct :methods [ [ asVec [ ] clojure.lang.IPersistentVector ] [ asMap [ ] clojure.lang.IPersistentMap ] ] )
( deftype VecSeq [ ^ clojure.lang.IPersistentVector v ^ int i ]
clojure.lang.ISeq clojure.lang.Indexed
( first [ this ] ( .nth v i ) )
( next [ this ] ( if ( < i ( dec ( .count v ) ) ) ( VecSeq. v ( inc i ) ) nil ) )
( more [ this ] ( if ( < i ( dec ( .count v ) ) ) ( VecSeq. v ( inc i ) ) [ ] ) )
( cons [ this o ] ( clojure.lang.Cons. o this ) )
( count [ this ] ( - ( .count v ) i ) )
( empty [ this ] nil )
( equiv [ this o ] ( = ( subvec v i ) o ) )
( nth [ this j ] ( .nth v ( + i j ) ) )
( nth [ this j o ] ( .nth v ( + i j ) o ) )
( seq [ this ] this )
)
( deftype VecWrap [ ^ coffi.mem.IStructImpl org ]
coffi.mem.IStruct clojure.lang.IPersistentVector Iterable
( length [ this ] ( .vec_length org ) )
( assocN [ this i v ] ( .vec_assocN org i v ) )
( peek [ this ] ( .vec_peek org ) )
( pop [ this ] ( .vec_pop org ) )
( nth [ this i ] ( .vec_nth org i ) )
( nth [ this i o ] ( .vec_nth org i o ) )
( cons [ this o ] ( .vec_cons org o ) )
( equiv [ this o ] ( .vec_equiv org o ) )
( empty [ this ] ( .vec_empty org ) )
( iterator [ this ] ( .vec_iterator org ) )
( forEach [ this c ] ( .vec_forEach org c ) )
( seq [ this ] ( VecSeq. this 0 ) )
( rseq [ this ] ( .vec_rseq org ) )
( count [ this ] ( .struct_count org ) )
( assoc [ this k v ] ( .struct_assoc org k v ) )
( containsKey [ this k ] ( .struct_containsKey org k ) )
( valAt [ this k ] ( .struct_valAt org k ) )
( valAt [ this k o ] ( .struct_valAt org k o ) )
( entryAt [ this k ] ( .struct_entryAt org k ) )
( asMap [ this ] org )
( asVec [ this ] this ) )
( deftype MapWrap [ ^ coffi.mem.IStructImpl org ]
coffi.mem.IStruct clojure.lang.IPersistentMap
( cons [ this o ] ( .map_cons org o ) )
( equiv [ this o ] ( .map_equiv org o ) )
( empty [ this ] ( .map_empty org ) )
( iterator [ this ] ( .map_iterator org ) )
( forEach [ this c ] ( .map_foreach org c ) )
( seq [ this ] ( .map_seq org ) )
( count [ this ] ( .struct_count org ) )
( assoc [ this k v ] ( .struct_assoc org k v ) )
( containsKey [ this k ] ( .struct_containsKey org k ) )
( valAt [ this k ] ( .struct_valAt org k ) )
( valAt [ this k o ] ( .struct_valAt org k o ) )
( entryAt [ this k ] ( .struct_entryAt org k ) )
( assocEx [ this k v ] ( .map_assocEx org k v ) )
( without [ this k ] ( .map_without org k ) )
( asMap [ this ] this )
( asVec [ this ] org ) )
( defn as-vec [ ^ coffi.mem.IStruct struct ] ( .asVec struct ) )
( defn as-map [ ^ coffi.mem.IStruct struct ] ( .asMap struct ) )
( defn- generate-struct-type [ typename typed-member-symbols maplike? ]
2024-10-12 13:52:03 +00:00
( let [ members ( map ( comp keyword str ) typed-member-symbols )
2024-10-18 16:06:02 +00:00
as-vec ( vec ( map ( comp symbol name ) members ) )
as-map ( into { } ( map ( fn [ m ] [ m ( symbol ( name m ) ) ] ) members ) ) ]
2024-10-19 01:26:45 +00:00
( letfn [ ( vec-length [ ] ( list 'length [ 'this ] ( count members ) ) )
( vec-assocN [ ] ( list 'assocN [ 'this 'i 'value ] ( list ` assoc 'i as-vec 'value ) ) )
( vec-peek [ ] ( list 'peek [ 'this ] ( first as-vec ) ) )
( vec-pop [ ] ( list 'pop [ 'this ] ( vec ( rest as-vec ) ) ) )
( vec-nth [ ] ( list 'nth [ 'this 'i ] ( concat [ ` case 'i ] ( interleave ( range ) as-vec ) ) ) )
( vec-nth-2 [ ] ( list 'nth [ 'this 'i 'o ] ( concat [ ` case 'i ] ( interleave ( range ) as-vec ) [ 'o ] ) ) )
( vec-cons [ ] ( list 'cons [ 'this 'o ] ( vec ( cons 'o as-vec ) ) ) )
( vec-equiv [ ] ( list 'equiv [ 'this 'o ] ( list ` = as-vec 'o ) ) )
( vec-empty [ ] ( list 'empty [ 'this ] [ ] ) )
( vec-iterator [ ] ( list 'iterator [ 'this ] ( list '.iterator as-vec ) ) )
( vec-foreach [ ] ( concat [ 'forEach [ 'this 'action ] ] ( partition 2 ( interleave ( repeat 'action ) as-vec ) ) ) )
( vec-seq [ ] ( list 'seq [ 'this ] ( list ` VecSeq. 'this 0 ) # _ ( list ` seq as-vec ) ) )
( vec-rseq [ ] ( list 'rseq [ 'this ] ( list ` seq ( vec ( reverse as-vec ) ) ) ) )
( s-count [ ] ( list 'count [ 'this ] ( count members ) ) )
( s-assoc [ ] ( list 'assoc [ 'this 'i 'value ] ( list ` if ( list ` number? 'i ) ( list ` assoc as-vec 'i 'value ) ( assoc as-map 'i 'value ) ) ) )
( s-containsKey [ ] ( list 'containsKey [ 'this 'k ] ( list ` if ( list ` number? 'k ) ( list ` and ( list ` >= 'k 0 ) ( list ` < 'k ( count members ) ) ) ( list ( set members ) 'k ) ) ) )
( s-valAt [ ] ( list 'valAt [ 'this 'k ] ( concat [ ` case 'k ] ( interleave ( range ) as-vec ) ( interleave members as-vec ) ) ) )
( s-valAt-2 [ ] ( list 'valAt [ 'this 'k 'o ] ( concat [ ` case 'k ] ( interleave ( range ) as-vec ) ( interleave members as-vec ) [ 'o ] ) ) )
( s-entryAt [ ] ( list 'entryAt [ 'this 'k ] ( list ` clojure.lang.MapEntry/create 'k ( concat [ ` case 'k ] ( interleave ( range ) as-vec ) ( interleave members as-vec ) ) ) ) )
( map-assocEx [ ] ( list 'assocEx [ 'this 'i 'value ] ( list ` if ( list ( set members ) 'i ) ( list ` throw ( list ` Exception. "key already exists" ) ) ( assoc as-map 'i 'value ) ) ) )
( map-without [ ] ( list 'without [ 'this 'k ] ( list ` dissoc as-map ( list ` if ( list ` number? 'k ) ( list ( vec members ) 'k ) 'k ) ) ) )
( map-cons [ ] ( list 'cons [ 'this 'o ] ( vec ( cons 'o as-map ) ) ) )
( map-equiv [ ] ( list 'equiv [ 'this 'o ] ( list ` = as-map 'o ) ) )
( map-empty [ ] ( list 'empty [ 'this ] { } ) )
( map-iterator [ ] ( list 'iterator [ 'this ] ( list '.iterator as-map ) ) )
( map-foreach [ ] ( concat [ 'forEach [ 'this 'action ] ] ( partition 2 ( interleave ( repeat 'action ) as-map ) ) ) )
( map-seq [ ] ( list 'seq [ 'this ] ( list ` seq ( vec ( map ( fn [ [ k v ] ] ( list ` clojure.lang.MapEntry/create k v ) ) ( partition 2 ( interleave members as-vec ) ) ) ) ) ) )
( map-methods [ ] [ ( map-without ) ( map-cons ) ( map-equiv ) ( map-empty ) ( map-iterator ) ( map-foreach ) ( map-seq ) ( map-assocEx ) ] )
( vec-methods [ ] [ ( vec-length ) ( vec-assocN ) ( vec-peek ) ( vec-pop ) ( vec-nth ) ( vec-nth-2 ) ( vec-cons ) ( vec-equiv ) ( vec-empty ) ( vec-iterator ) ( vec-foreach ) ( vec-seq ) ( vec-rseq ) ] )
( struct-methods [ ] [ ( s-count ) ( s-assoc ) ( s-containsKey ) ( s-valAt ) ( s-valAt-2 ) ( s-entryAt ) ] )
( prefix-methods [ prefix ms ] ( map ( fn [ [ method-name & tail ] ] ( cons ( symbol ( str prefix method-name ) ) tail ) ) ms ) )
( impl-methods [ ] ( concat ( prefix-methods "map_" ( map-methods ) ) ( prefix-methods "vec_" ( vec-methods ) ) ( prefix-methods "struct_" ( struct-methods ) ) ) )
]
( if maplike?
( concat
[ ` deftype ( symbol ( name typename ) ) ( vec typed-member-symbols ) ` coffi.mem.IStruct ` coffi.mem.IStructImpl ` clojure.lang.IPersistentMap ]
( struct-methods )
( map-methods )
( impl-methods )
[ ( list 'asMap [ 'this ] 'this )
( list 'asVec [ 'this ] ( list ` VecWrap. 'this ) ) ] )
( concat
[ ` deftype ( symbol ( name typename ) ) ( vec typed-member-symbols ) ` coffi.mem.IStruct ` clojure.lang.IPersistentVector ]
( struct-methods )
( vec-methods )
[ ( list 'asMap [ 'this ]
( list ` proxy [ ` coffi.mem.IStruct ` clojure.lang.IPersistentVector ] [ ]
( concat ( struct-methods ) ( map-methods ) [ ( list 'asMap [ 'newthis ] 'this ) ( list 'asVec [ 'newthis ] 'newthis ) ] ) ) )
( list 'asVec [ 'this ] 'this ) ] ) ) ) ) )
2024-10-12 13:52:03 +00:00
2024-10-11 12:25:18 +00:00
( defmacro defstruct
2024-10-11 22:36:21 +00:00
" Defines a struct type. all members need to be supplied in pairs of ` coffi-type member-name ` .
2024-10-11 12:25:18 +00:00
2024-10-11 22:36:21 +00:00
This creates needed serialization and deserialization implementations for the new type. "
2024-10-11 12:25:18 +00:00
{ :style/indent [ :defn ] }
[ typename members ]
( cond
2024-10-11 22:36:21 +00:00
( 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 `typename member-name`. the typename has to be coffi typename, like `:coffi.mem/int` or `[:coffi.mem/array :coffi.mem/byte 3]`" ) )
2024-10-11 12:25:18 +00:00
: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 )
2024-10-11 22:36:21 +00:00
( map ( fn [ [ _type sym ] ] ( with-meta sym { :tag ( coffitype->typename _type ) } ) ) )
2024-10-11 12:25:18 +00:00
( vec ) )
2024-10-11 13:18:35 +00:00
struct-layout ( with-c-layout [ ::struct
( ->>
members
( partition 2 2 )
( map vec )
( 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 15:48:58 +00:00
( register-new-struct-serialization coffi-typename struct-layout )
2024-10-11 12:25:18 +00:00
` ( do
2024-10-19 01:26:45 +00:00
~ ( generate-struct-type typename typed-symbols true )
2024-10-11 20:26:41 +00:00
( defmethod c-layout ~ coffi-typename [ ~ '_ ] ( c-layout ~ struct-layout ) )
2024-10-11 13:52:40 +00:00
( defmethod deserialize-from ~ coffi-typename ~ [ 'segment '_type ]
2024-10-11 20:26:41 +00:00
~ ( first ( generate-deserialize coffi-typename 0 ) ) )
2024-10-11 15:48:58 +00:00
( defmethod serialize-into ~ coffi-typename ~ [ ( with-meta 'source-obj { :tag typename } ) '_type 'segment '_ ]
~ ( generate-serialize coffi-typename ( with-meta 'source-obj { :tag typename } ) 0 ) )
2024-10-13 20:08:01 +00:00
( defmethod clojure.pprint/simple-dispatch ~ typename [ ~ 'obj ] ( clojure.pprint/simple-dispatch ( into { } ~ 'obj ) ) )
2024-10-19 01:26:45 +00:00
( defmethod clojure.core/print-method ~ typename [ ~ 'obj ~ 'writer ] ( print-simple ( into { } ~ 'obj ) ~ 'writer ) )
2024-10-11 12:25:18 +00:00
)
)
)
)
2024-10-10 13:59:28 +00:00