From b5d317037297f70a57ba908c43868fb7b24eba1a Mon Sep 17 00:00:00 2001 From: Joshua Suskalo Date: Sun, 23 Jan 2022 20:28:56 -0600 Subject: [PATCH 01/11] Add unreleased section to changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a46187..f953948 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Change Log All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). +## [Unreleased] + ## [0.4.341] - 2022-01-23 ### Added - Constants for size and alignment of primitive types @@ -91,6 +93,7 @@ All notable changes to this project will be documented in this file. This change - Support for serializing and deserializing arbitrary Clojure functions - Support for serializing and deserializing arbitrary Clojure data structures +[Unreleased]: https://github.com/IGJoshua/coffi/compare/v0.4.341...develop [0.4.341]: https://github.com/IGJoshua/coffi/compare/v0.3.298...v0.4.341 [0.3.298]: https://github.com/IGJoshua/coffi/compare/v0.2.277...v0.3.298 [0.2.277]: https://github.com/IGJoshua/coffi/compare/v0.2.259...v0.2.277 From cf5c39dfd6a50f0253547eec79227ce3e3e61b3d Mon Sep 17 00:00:00 2001 From: Joshua Suskalo Date: Mon, 11 Apr 2022 17:09:22 -0500 Subject: [PATCH 02/11] Update future plans for some todos --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9a94b2d..ddd50a9 100644 --- a/README.md +++ b/README.md @@ -1084,6 +1084,8 @@ These features are planned for future releases. - Header parsing tool for generating a data model? - Generic type aliases - Helpers for generating enums & bitflags +- Unsigned integer types +- Record-based struct types - Helper macro for out arguments - Improve error messages from defcfn macro - Mapped memory From 709e2c1dc94f672ac1b59a30655c95d18b59501b Mon Sep 17 00:00:00 2001 From: Joshua Suskalo Date: Fri, 15 Apr 2022 09:58:10 -0500 Subject: [PATCH 03/11] Update to jdk 18 in changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f953948..dc60fad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). ## [Unreleased] +### Changed +- JDK version from 17 to 18 ## [0.4.341] - 2022-01-23 ### Added From 5d24b149928496decd01adb4b2f84cac5c0a583e Mon Sep 17 00:00:00 2001 From: Joshua Suskalo Date: Fri, 15 Apr 2022 09:56:08 -0500 Subject: [PATCH 04/11] Update the build to produce the correct version of jvm bytecode --- build.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.clj b/build.clj index c0df6d7..5c7e0b2 100644 --- a/build.clj +++ b/build.clj @@ -52,8 +52,8 @@ (b/process {:command-args ["javac" "--add-modules=jdk.incubator.foreign" "src/java/coffi/ffi/Loader.java" "-d" class-dir - "-target" "17" - "-source" "17"]}) + "-target" "18" + "-source" "18"]}) opts) (defn- write-pom From 4037040c4b8f52ce35c4d04be1a71fd9a03936c7 Mon Sep 17 00:00:00 2001 From: Joshua Suskalo Date: Fri, 15 Apr 2022 09:56:38 -0500 Subject: [PATCH 05/11] Update mem namespace to jdk18 --- CHANGELOG.md | 4 + src/clj/coffi/mem.clj | 402 +++++++++++++++++++++++------------------- 2 files changed, 222 insertions(+), 184 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc60fad..3a0fd9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,11 @@ All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). ## [Unreleased] +### Removed +- `coffi.mem/slice-into` function no longer has an equivalent in panama, but see 2-arity of `coffi.mem/as-segment` for an alternative + ### Changed +- `coffi.mem/as-segment` no longer has a close action arity - JDK version from 17 to 18 ## [0.4.341] - 2022-01-23 diff --git a/src/clj/coffi/mem.clj b/src/clj/coffi/mem.clj index 492f786..87fb28a 100644 --- a/src/clj/coffi/mem.clj +++ b/src/clj/coffi/mem.clj @@ -24,15 +24,13 @@ (java.nio ByteOrder) (jdk.incubator.foreign Addressable - CLinker - MemoryAccess MemoryAddress MemoryLayout MemorySegment ResourceScope - ResourceScope$Handle SegmentAllocator - ValueLayout))) + ValueLayout + ValueLayout$OfAddress))) (defn stack-scope "Constructs a new scope for use only in this thread. @@ -78,7 +76,7 @@ downcall function returns a non-primitive type, it must be provided with an allocator." ^SegmentAllocator [^ResourceScope scope] - (SegmentAllocator/ofScope scope)) + (SegmentAllocator/nativeAllocator scope)) (defn segment-scope "Gets the scope used to construct the `segment`." @@ -107,15 +105,10 @@ with it wrapped in this." {:style/indent 1} [scopes & body] - `(let [scopes# (vec ~scopes) - handles# (mapv #(.acquire ^ResourceScope %) scopes#)] - (try ~@body - (finally - (doseq [idx# (range (count scopes#)) - :let [scope# (nth scopes# idx#) - handle# (nth handles# idx#)]] - (.release ^ResourceScope scope# - ^ResourceScope$Handle handle#)))))) + `(with-open [scope# (stack-scope)] + (doseq [target-scope# (vec ~scopes)] + (.keepAlive scope# target-scope#)) + ~@body)) (s/fdef with-acquired :args (s/cat :scopes any? :body (s/* any?))) @@ -139,16 +132,6 @@ [addr] (or (nil? addr) (instance? MemoryAddress addr))) -(defn slice-global - "Gets a slice of the global address space. - - Because this fetches from the global segment, it has no associated scope, and - therefore the reference created here cannot prevent the value from being - freed. Be careful to ensure that you are not retaining an object incorrectly." - ^MemorySegment [address size] - (.asSlice (MemorySegment/globalNativeSegment) - ^MemoryAddress address (long size))) - (defn slice "Get a slice over the `segment` with the given `offset`." (^MemorySegment [segment offset] @@ -168,25 +151,19 @@ ^MemoryAddress [address offset] (.addOffset ^MemoryAddress address (long offset))) -(defn as-segment - "Dereferences an `address` into a memory segment associated with the `scope`. - - If `cleanup` is provided, it is a 0-arity function run when the scope is - closed. This can be used to register a free method for the memory, or do other - cleanup in a way that doesn't require modifying the code at the point of - freeing, and allows shared or garbage collected resources to be freed - correctly." - (^MemorySegment [^MemoryAddress address size scope] - (.asSegment address (long size) scope)) - (^MemorySegment [^MemoryAddress address size ^ResourceScope scope cleanup] - (.asSegment address (long size) cleanup scope))) - (defn add-close-action! "Adds a 0-arity function to be run when the `scope` closes." [^ResourceScope scope ^Runnable action] (.addCloseAction scope action) nil) +(defn as-segment + "Dereferences an `address` into a memory segment associated with the `scope`." + (^MemorySegment [^MemoryAddress address size] + (MemorySegment/ofAddress address (long size) (connected-scope))) + (^MemorySegment [^MemoryAddress address size scope] + (MemorySegment/ofAddress address (long size) scope))) + (defn copy-segment "Copies the content to `dest` from `src`. @@ -230,39 +207,35 @@ (def ^ValueLayout byte-layout "The [[MemoryLayout]] for a byte in [[native-endian]] [[ByteOrder]]." - CLinker/C_CHAR) + (MemoryLayout/valueLayout Byte/TYPE native-endian)) (def ^ValueLayout short-layout "The [[MemoryLayout]] for a c-sized short in [[native-endian]] [[ByteOrder]]." - CLinker/C_SHORT) + (MemoryLayout/valueLayout Short/TYPE native-endian)) (def ^ValueLayout int-layout "The [[MemoryLayout]] for a c-sized int in [[native-endian]] [[ByteOrder]]." - CLinker/C_INT) + (MemoryLayout/valueLayout Integer/TYPE native-endian)) (def ^ValueLayout long-layout "The [[MemoryLayout]] for a c-sized long in [[native-endian]] [[ByteOrder]]." - CLinker/C_LONG) - -(def ^ValueLayout long-long-layout - "The [[MemoryLayout]] for a c-sized long-long in [[native-endian]] [[ByteOrder]]." - CLinker/C_LONG_LONG) + (MemoryLayout/valueLayout Long/TYPE native-endian)) (def ^ValueLayout char-layout "The [[MemoryLayout]] for a c-sized char in [[native-endian]] [[ByteOrder]]." - CLinker/C_CHAR) + (MemoryLayout/valueLayout Byte/TYPE native-endian)) (def ^ValueLayout float-layout "The [[MemoryLayout]] for a c-sized float in [[native-endian]] [[ByteOrder]]." - CLinker/C_FLOAT) + (MemoryLayout/valueLayout Float/TYPE native-endian)) (def ^ValueLayout double-layout "The [[MemoryLayout]] for a c-sized double in [[native-endian]] [[ByteOrder]]." - CLinker/C_DOUBLE) + (MemoryLayout/valueLayout Double/TYPE native-endian)) -(def ^ValueLayout pointer-layout +(def ^ValueLayout$OfAddress pointer-layout "The [[MemoryLayout]] for a native pointer in [[native-endian]] [[ByteOrder]]." - CLinker/C_POINTER) + ValueLayout/ADDRESS) (def ^long short-size "The size in bytes of a c-sized short." @@ -276,10 +249,6 @@ "The size in bytes of a c-sized long." (.byteSize long-layout)) -(def ^long long-long-size - "The size in bytes of a c-sized long long." - (.byteSize long-long-layout)) - (def ^long float-size "The size in bytes of a c-sized float." (.byteSize float-layout)) @@ -304,10 +273,6 @@ "The alignment in bytes of a c-sized long." (.byteAlignment long-layout)) -(def ^long long-long-alignment - "The alignment in bytes of a c-sized long long." - (.byteAlignment long-long-layout)) - (def ^long float-alignment "The alignment in bytes of a c-sized float." (.byteAlignment float-layout)) @@ -325,13 +290,16 @@ {:inline (fn read-byte-inline ([segment] - `(MemoryAccess/getByte ~segment)) + `(let [segment# ~segment] + (.get ^MemorySegment segment# ^ValueLayout byte-layout 0))) ([segment offset] - `(MemoryAccess/getByteAtOffset ~segment ~offset)))} + `(let [segment# ~segment + offset# ~offset] + (.get ^MemorySegment segment# ^ValueLayout byte-layout offset#))))} ([^MemorySegment segment] - (MemoryAccess/getByte segment)) + (.get segment ^ValueLayout byte-layout 0)) ([^MemorySegment segment ^long offset] - (MemoryAccess/getByteAtOffset segment offset))) + (.get segment ^ValueLayout byte-layout offset))) (defn read-short "Reads a [[short]] from the `segment`, at an optional `offset`. @@ -340,17 +308,23 @@ {:inline (fn read-short-inline ([segment] - `(MemoryAccess/getShort ~segment)) + `(let [segment# ~segment] + (.get ^MemorySegment segment# ^ValueLayout short-layout 0))) ([segment offset] - `(MemoryAccess/getShortAtOffset ~segment ~offset)) + `(let [segment# ~segment + offset# ~offset] + (.get ^MemorySegment segment# ^ValueLayout short-layout offset#))) ([segment offset byte-order] - `(MemoryAccess/getShortAtOffset ~segment ~offset ~byte-order)))} + `(let [segment# ~segment + offset# ~offset + byte-order# ~byte-order] + (.get ^MemorySegment segment# (.withOrder ^ValueLayout short-layout ^ByteOrder byte-order#) offset#))))} ([^MemorySegment segment] - (MemoryAccess/getShort segment)) + (.get segment ^ValueLayout short-layout 0)) ([^MemorySegment segment ^long offset] - (MemoryAccess/getShortAtOffset segment offset)) + (.get segment ^ValueLayout short-layout offset)) ([^MemorySegment segment ^long offset ^ByteOrder byte-order] - (MemoryAccess/getShortAtOffset segment offset byte-order))) + (.get segment (.withOrder ^ValueLayout short-layout byte-order) offset))) (defn read-int "Reads a [[int]] from the `segment`, at an optional `offset`. @@ -359,17 +333,23 @@ {:inline (fn read-int-inline ([segment] - `(MemoryAccess/getInt ~segment)) + `(let [segment# ~segment] + (.get ^MemorySegment segment# ^ValueLayout int-layout 0))) ([segment offset] - `(MemoryAccess/getIntAtOffset ~segment ~offset)) + `(let [segment# ~segment + offset# ~offset] + (.get ^MemorySegment segment# ^ValueLayout int-layout offset#))) ([segment offset byte-order] - `(MemoryAccess/getIntAtOffset ~segment ~offset ~byte-order)))} + `(let [segment# ~segment + offset# ~offset + byte-order# ~byte-order] + (.get ^MemorySegment segment# (.withOrder ^ValueLayout int-layout ^ByteOrder byte-order#) offset#))))} ([^MemorySegment segment] - (MemoryAccess/getInt segment)) + (.get segment ^ValueLayout int-layout 0)) ([^MemorySegment segment ^long offset] - (MemoryAccess/getIntAtOffset segment offset)) + (.get segment ^ValueLayout int-layout offset)) ([^MemorySegment segment ^long offset ^ByteOrder byte-order] - (MemoryAccess/getIntAtOffset segment offset byte-order))) + (.get segment (.withOrder ^ValueLayout int-layout byte-order) offset))) (defn read-long "Reads a [[long]] from the `segment`, at an optional `offset`. @@ -378,30 +358,39 @@ {:inline (fn read-long-inline ([segment] - `(MemoryAccess/getLong ~segment)) + `(let [segment# ~segment] + (.get ^MemorySegment segment# ^ValueLayout long-layout 0))) ([segment offset] - `(MemoryAccess/getLongAtOffset ~segment ~offset)) + `(let [segment# ~segment + offset# ~offset] + (.get ^MemorySegment segment# ^ValueLayout long-layout offset#))) ([segment offset byte-order] - `(MemoryAccess/getLongAtOffset ~segment ~offset ~byte-order)))} + `(let [segment# ~segment + offset# ~offset + byte-order# ~byte-order] + (.get ^MemorySegment segment# (.withOrder ^ValueLayout long-layout ^ByteOrder byte-order#) offset#))))} (^long [^MemorySegment segment] - (MemoryAccess/getLong segment)) + (.get segment ^ValueLayout long-layout 0)) (^long [^MemorySegment segment ^long offset] - (MemoryAccess/getLongAtOffset segment offset)) + (.get segment ^ValueLayout long-layout offset)) (^long [^MemorySegment segment ^long offset ^ByteOrder byte-order] - (MemoryAccess/getLongAtOffset segment offset byte-order))) + (.get segment (.withOrder ^ValueLayout long-layout byte-order) offset))) (defn read-char "Reads a [[char]] from the `segment`, at an optional `offset`." {:inline (fn read-char-inline ([segment] - `(char (Byte/toUnsignedInt (MemoryAccess/getByte ~segment)))) + `(let [segment# ~segment] + (char (Byte/toUnsignedInt (.get ^MemorySegment segment# ^ValueLayout byte-layout 0))))) ([segment offset] - `(char (Byte/toUnsignedInt (MemoryAccess/getByteAtOffset ~segment ~offset)))))} + `(let [segment# ~segment + offset# ~offset] + (char (Byte/toUnsignedInt (.get ^MemorySegment segment# ^ValueLayout byte-layout offset#))))))} ([^MemorySegment segment] - (char (Byte/toUnsignedInt (MemoryAccess/getByte segment)))) + (char (Byte/toUnsignedInt (.get segment ^ValueLayout byte-layout 0)))) ([^MemorySegment segment ^long offset] - (char (Byte/toUnsignedInt (MemoryAccess/getByteAtOffset segment offset))))) + (char (Byte/toUnsignedInt (.get segment ^ValueLayout byte-layout offset))))) (defn read-float "Reads a [[float]] from the `segment`, at an optional `offset`. @@ -410,17 +399,23 @@ {:inline (fn read-float-inline ([segment] - `(MemoryAccess/getFloat ~segment)) + `(let [segment# ~segment] + (.get ^MemorySegment segment# ^ValueLayout float-layout 0))) ([segment offset] - `(MemoryAccess/getFloatAtOffset ~segment ~offset)) + `(let [segment# ~segment + offset# ~offset] + (.get ^MemorySegment segment# ^ValueLayout float-layout offset#))) ([segment offset byte-order] - `(MemoryAccess/getFloatAtOffset ~segment ~offset ~byte-order)))} + `(let [segment# ~segment + offset# ~offset + byte-order# ~byte-order] + (.get ^MemorySegment segment# (.withOrder ^ValueLayout float-layout ^ByteOrder byte-order#) offset#))))} ([^MemorySegment segment] - (MemoryAccess/getFloat segment)) + (.get segment ^ValueLayout float-layout 0)) ([^MemorySegment segment ^long offset] - (MemoryAccess/getFloatAtOffset segment offset)) + (.get segment ^ValueLayout float-layout offset)) ([^MemorySegment segment ^long offset ^ByteOrder byte-order] - (MemoryAccess/getFloatAtOffset segment offset byte-order))) + (.get segment (.withOrder ^ValueLayout float-layout byte-order) offset))) (defn read-double "Reads a [[double]] from the `segment`, at an optional `offset`. @@ -429,43 +424,57 @@ {:inline (fn read-double-inline ([segment] - `(MemoryAccess/getDouble ~segment)) + `(let [segment# ~segment] + (.get ^MemorySegment segment# ^ValueLayout double-layout 0))) ([segment offset] - `(MemoryAccess/getDoubleAtOffset ~segment ~offset)) + `(let [segment# ~segment + offset# ~offset] + (.get ^MemorySegment segment# ^ValueLayout double-layout offset#))) ([segment offset byte-order] - `(MemoryAccess/getDoubleAtOffset ~segment ~offset ~byte-order)))} + `(let [segment# ~segment + offset# ~offset + byte-order# ~byte-order] + (.get ^MemorySegment segment# (.withOrder ^ValueLayout double-layout ^ByteOrder byte-order#) offset#))))} (^double [^MemorySegment segment] - (MemoryAccess/getDouble segment)) + (.get segment ^ValueLayout double-layout 0)) (^double [^MemorySegment segment ^long offset] - (MemoryAccess/getDoubleAtOffset segment offset)) + (.get segment ^ValueLayout double-layout offset)) (^double [^MemorySegment segment ^long offset ^ByteOrder byte-order] - (MemoryAccess/getDoubleAtOffset segment offset byte-order))) + (.get segment (.withOrder ^ValueLayout double-layout byte-order) offset))) (defn read-address "Reads a [[MemoryAddress]] from the `segment`, at an optional `offset`." {:inline (fn read-address-inline ([segment] - `(MemoryAccess/getAddress ~segment)) + `(let [segment# ~segment] + (.get ^MemorySegment segment# ^ValueLayout$OfAddress pointer-layout 0))) ([segment offset] - `(MemoryAccess/getAddressAtOffset ~segment ~offset)))} + `(let [segment# ~segment + offset# ~offset] + (.get ^MemorySegment segment# ^ValueLayout$OfAddress pointer-layout offset#))))} (^MemoryAddress [^MemorySegment segment] - (MemoryAccess/getAddress segment)) + (.get segment ^ValueLayout$OfAddress pointer-layout 0)) (^MemoryAddress [^MemorySegment segment ^long offset] - (MemoryAccess/getAddressAtOffset segment offset))) + (.get segment ^ValueLayout$OfAddress pointer-layout offset))) (defn write-byte "Writes a [[byte]] to the `segment`, at an optional `offset`." {:inline (fn write-byte-inline ([segment value] - `(MemoryAccess/setByte ~segment ~value)) + `(let [segment# ~segment + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout byte-layout 0 value#))) ([segment offset value] - `(MemoryAccess/setByteAtOffset ~segment ~offset ~value)))} + `(let [segment# ~segment + offset# ~offset + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout byte-layout offset# value#))))} ([^MemorySegment segment value] - (MemoryAccess/setByte segment ^byte value)) + (.set segment ^ValueLayout byte-layout 0 ^byte value)) ([^MemorySegment segment ^long offset value] - (MemoryAccess/setByteAtOffset segment offset ^byte value))) + (.set segment ^ValueLayout byte-layout offset ^byte value))) (defn write-short "Writes a [[short]] to the `segment`, at an optional `offset`. @@ -474,17 +483,26 @@ {:inline (fn write-short-inline ([segment value] - `(MemoryAccess/setShort ~segment ~value)) + `(let [segment# ~segment + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout short-layout 0 value#))) ([segment offset value] - `(MemoryAccess/setShortAtOffset ~segment ~offset ~value)) + `(let [segment# ~segment + offset# ~offset + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout short-layout offset# value#))) ([segment offset byte-order value] - `(MemoryAccess/setShortAtOffset ~segment ~offset ~byte-order ~value)))} + `(let [segment# ~segment + offset# ~offset + byte-order# ~byte-order + value# ~value] + (.set ^MemorySegment segment# (.withOrder ^ValueLayout short-layout ^ByteOrder byte-order#) offset# value#))))} ([^MemorySegment segment value] - (MemoryAccess/setShort segment ^short value)) + (.set segment ^ValueLayout short-layout 0 ^short value)) ([^MemorySegment segment ^long offset value] - (MemoryAccess/setShortAtOffset segment offset ^short value)) + (.set segment ^ValueLayout short-layout offset ^short value)) ([^MemorySegment segment ^long offset ^ByteOrder byte-order value] - (MemoryAccess/setShortAtOffset segment offset byte-order ^short value))) + (.set segment (.withOrder ^ValueLayout short-layout byte-order) offset ^short value))) (defn write-int "Writes a [[int]] to the `segment`, at an optional `offset`. @@ -493,17 +511,26 @@ {:inline (fn write-int-inline ([segment value] - `(MemoryAccess/setInt ~segment ~value)) + `(let [segment# ~segment + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout int-layout 0 value#))) ([segment offset value] - `(MemoryAccess/setIntAtOffset ~segment ~offset ~value)) + `(let [segment# ~segment + offset# ~offset + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout int-layout offset# value#))) ([segment offset byte-order value] - `(MemoryAccess/setIntAtOffset ~segment ~offset ~byte-order ~value)))} + `(let [segment# ~segment + offset# ~offset + byte-order# ~byte-order + value# ~value] + (.set ^MemorySegment segment# (.withOrder ^ValueLayout int-layout ^ByteOrder byte-order#) offset# value#))))} ([^MemorySegment segment value] - (MemoryAccess/setInt segment ^int value)) + (.set segment ^ValueLayout int-layout 0 ^int value)) ([^MemorySegment segment ^long offset value] - (MemoryAccess/setIntAtOffset segment offset ^int value)) + (.set segment ^ValueLayout int-layout offset ^int value)) ([^MemorySegment segment ^long offset ^ByteOrder byte-order value] - (MemoryAccess/setIntAtOffset segment offset byte-order ^int value))) + (.set segment (.withOrder ^ValueLayout int-layout byte-order) offset ^int value))) (defn write-long "Writes a [[long]] to the `segment`, at an optional `offset`. @@ -512,35 +539,50 @@ {:inline (fn write-long-inline ([segment value] - `(MemoryAccess/setLong ~segment ~value)) + `(let [segment# ~segment + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout long-layout 0 value#))) ([segment offset value] - `(MemoryAccess/setLongAtOffset ~segment ~offset ~value)) + `(let [segment# ~segment + offset# ~offset + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout long-layout offset# value#))) ([segment offset byte-order value] - `(MemoryAccess/setLongAtOffset ~segment ~offset ~byte-order ~value)))} + `(let [segment# ~segment + offset# ~offset + byte-order# ~byte-order + value# ~value] + (.set ^MemorySegment segment# (.withOrder ^ValueLayout long-layout ^ByteOrder byte-order#) offset# value#))))} (^long [^MemorySegment segment ^long value] - (MemoryAccess/setLong segment value)) + (.set segment ^ValueLayout long-layout 0 value)) (^long [^MemorySegment segment ^long offset ^long value] - (MemoryAccess/setLongAtOffset segment offset value)) + (.set segment ^ValueLayout long-layout offset value)) (^long [^MemorySegment segment ^long offset ^ByteOrder byte-order ^long value] - (MemoryAccess/setLongAtOffset segment offset byte-order value))) + (.set segment (.withOrder ^ValueLayout long-layout byte-order) offset value))) (defn write-char "Writes a [[char]] to the `segment`, at an optional `offset`." {:inline (fn write-char-inline ([segment value] - `(MemoryAccess/setByte ~segment (unchecked-byte (unchecked-int ~value)))) + `(let [segment# ~segment + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout byte-layout 0 (unchecked-byte (unchecked-int value#))))) ([segment offset value] - `(MemoryAccess/setByteAtOffset ~segment ~offset (unchecked-byte (unchecked-int ~value)))))} + `(let [segment# ~segment + offset# ~offset + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout byte-layout offset# (unchecked-byte (unchecked-int value#))))))} ([^MemorySegment segment value] - (MemoryAccess/setByte + (.set 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. + ^ValueLayout byte-layout 0 (unchecked-byte (unchecked-int ^char value)))) ([^MemorySegment segment ^long offset value] - (MemoryAccess/setByteAtOffset segment offset (unchecked-byte (unchecked-int ^char value))))) + (.set segment ^ValueLayout byte-layout offset (unchecked-byte (unchecked-int ^char value))))) (defn write-float "Writes a [[float]] to the `segment`, at an optional `offset`. @@ -549,17 +591,26 @@ {:inline (fn write-float-inline ([segment value] - `(MemoryAccess/setFloat ~segment ~value)) + `(let [segment# ~segment + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout float-layout 0 value#))) ([segment offset value] - `(MemoryAccess/setFloatAtOffset ~segment ~offset ~value)) + `(let [segment# ~segment + offset# ~offset + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout float-layout offset# value#))) ([segment offset byte-order value] - `(MemoryAccess/setFloatAtOffset ~segment ~offset ~byte-order ~value)))} + `(let [segment# ~segment + offset# ~offset + byte-order# ~byte-order + value# ~value] + (.set ^MemorySegment segment# (.withOrder ^ValueLayout float-layout ^ByteOrder byte-order#) offset# value#))))} ([^MemorySegment segment value] - (MemoryAccess/setFloat segment ^float value)) + (.set segment ^ValueLayout float-layout 0 ^float value)) ([^MemorySegment segment ^long offset value] - (MemoryAccess/setFloatAtOffset segment offset ^float value)) + (.set segment ^ValueLayout float-layout offset ^float value)) ([^MemorySegment segment ^long offset ^ByteOrder byte-order value] - (MemoryAccess/setFloatAtOffset segment offset byte-order ^float value))) + (.set segment (.withOrder ^ValueLayout float-layout byte-order) offset ^float value))) (defn write-double "Writes a [[double]] to the `segment`, at an optional `offset`. @@ -568,30 +619,44 @@ {:inline (fn write-double-inline ([segment value] - `(MemoryAccess/setDouble ~segment ~value)) + `(let [segment# ~segment + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout double-layout 0 value#))) ([segment offset value] - `(MemoryAccess/setDoubleAtOffset ~segment ~offset ~value)) + `(let [segment# ~segment + offset# ~offset + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout double-layout offset# value#))) ([segment offset byte-order value] - `(MemoryAccess/setDoubleAtOffset ~segment ~offset ~byte-order ~value)))} + `(let [segment# ~segment + offset# ~offset + byte-order# ~byte-order + value# ~value] + (.set ^MemorySegment segment# (.withOrder ^ValueLayout double-layout ^ByteOrder byte-order#) offset# value#))))} (^double [^MemorySegment segment ^double value] - (MemoryAccess/setDouble segment value)) + (.set segment ^ValueLayout double-layout 0 value)) (^double [^MemorySegment segment ^long offset ^double value] - (MemoryAccess/setDoubleAtOffset segment offset value)) + (.set segment ^ValueLayout double-layout offset value)) (^double [^MemorySegment segment ^long offset ^ByteOrder byte-order ^double value] - (MemoryAccess/setDoubleAtOffset segment offset byte-order value))) + (.set segment (.withOrder ^ValueLayout double-layout byte-order) offset value))) (defn write-address "Writes a [[MemoryAddress]] to the `segment`, at an optional `offset`." {:inline (fn write-address-inline ([segment value] - `(MemoryAccess/setAddress ~segment ~value)) + `(let [segment# ~segment + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout$OfAddress pointer-layout 0 ^Addressable value#))) ([segment offset value] - `(MemoryAccess/setAddressAtOffset ~segment ~offset ~value)))} + `(let [segment# ~segment + offset# ~offset + value# ~value] + (.set ^MemorySegment segment# ^ValueLayout$OfAddress pointer-layout offset# ^Addressable value#))))} (^MemoryAddress [^MemorySegment segment ^MemoryAddress value] - (MemoryAccess/setAddress segment value)) + (.set segment ^ValueLayout$OfAddress pointer-layout 0 value)) (^MemoryAddress [^MemorySegment segment ^long offset ^MemoryAddress value] - (MemoryAccess/setAddressAtOffset segment offset value))) + (.set segment ^ValueLayout$OfAddress pointer-layout offset value))) (defn- type-dispatch "Gets a type dispatch value from a (potentially composite) type." @@ -603,7 +668,7 @@ (def primitive-types "A set of all primitive types." - #{::byte ::short ::int ::long ::long-long + #{::byte ::short ::int ::long ::char ::float ::double ::pointer}) (defn primitive? @@ -644,10 +709,6 @@ [_type] ::long) -(defmethod primitive-type ::long-long - [_type] - ::long-long) - (defmethod primitive-type ::char [_type] ::char) @@ -688,27 +749,21 @@ (defmethod c-layout ::short [type] (if (sequential? type) - (.withOrder short-layout (second type)) + (.withOrder short-layout ^ByteOrder (second type)) short-layout)) (defmethod c-layout ::int [type] (if (sequential? type) - (.withOrder int-layout (second type)) + (.withOrder int-layout ^ByteOrder (second type)) int-layout)) (defmethod c-layout ::long [type] (if (sequential? type) - (.withOrder long-layout (second type)) + (.withOrder long-layout ^ByteOrder (second type)) long-layout)) -(defmethod c-layout ::long-long - [type] - (if (sequential? type) - (.withOrder long-long-layout (second type)) - long-long-layout)) - (defmethod c-layout ::char [_type] char-layout) @@ -716,13 +771,13 @@ (defmethod c-layout ::float [type] (if (sequential? type) - (.withOrder float-layout (second type)) + (.withOrder float-layout ^ByteOrder (second type)) float-layout)) (defmethod c-layout ::double [type] (if (sequential? type) - (.withOrder double-layout (second type)) + (.withOrder double-layout ^ByteOrder (second type)) double-layout)) (defmethod c-layout ::pointer @@ -735,7 +790,6 @@ ::short Short/TYPE ::int Integer/TYPE ::long Long/TYPE - ::long-long Long/TYPE ::char Byte/TYPE ::float Float/TYPE ::double Double/TYPE @@ -805,10 +859,6 @@ [obj _type _scope] (long obj)) -(defmethod serialize* ::long-long - [obj _type _scope] - (long obj)) - (defmethod serialize* ::char [obj _type _scope] (char obj)) @@ -886,12 +936,6 @@ (write-long segment 0 (second type) (long obj)) (write-long segment (long obj)))) -(defmethod serialize-into ::long-long - [obj type segment _scope] - (if (sequential? type) - (write-long segment 0 (second type) (long obj)) - (write-long segment (long obj)))) - (defmethod serialize-into ::char [obj _type segment _scope] (write-char segment (char obj))) @@ -911,7 +955,7 @@ (defmethod serialize-into ::pointer [obj type segment scope] (with-acquired [(segment-scope segment) scope] - (MemoryAccess/setAddress + (write-address segment (cond-> obj (sequential? type) (serialize* type scope))))) @@ -977,12 +1021,6 @@ (read-long segment 0 (second type)) (read-long segment))) -(defmethod deserialize-from ::long-long - [segment type] - (if (sequential? type) - (read-long segment 0 (second type)) - (read-long segment))) - (defmethod deserialize-from ::char [segment _type] (read-char segment)) @@ -1002,7 +1040,7 @@ (defmethod deserialize-from ::pointer [segment type] (with-acquired [(segment-scope segment)] - (cond-> (MemoryAccess/getAddress segment) + (cond-> (read-address segment) (sequential? type) (deserialize* type)))) (defmulti deserialize* @@ -1037,10 +1075,6 @@ [obj _type] obj) -(defmethod deserialize* ::long-long - [obj _type] - obj) - (defmethod deserialize* ::char [obj _type] obj) @@ -1057,7 +1091,7 @@ [addr type] (when-not (null? addr) (if (sequential? type) - (deserialize-from (slice-global addr (size-of (second type))) + (deserialize-from (as-segment addr (size-of (second type))) (second type)) addr))) @@ -1092,13 +1126,13 @@ (defmethod serialize* ::c-string [obj _type scope] (if obj - (address-of (CLinker/toCString ^String obj ^ResourceScope scope)) + (address-of (.allocateUtf8String (scope-allocator scope) ^String obj)) (MemoryAddress/NULL))) (defmethod deserialize* ::c-string [addr _type] (when-not (null? addr) - (CLinker/toJavaString ^MemoryAddress addr))) + (.getUtf8String ^MemoryAddress addr 0))) ;;; Union types From b10c459bf71e2c7243d2f71de3de54543868a61c Mon Sep 17 00:00:00 2001 From: Joshua Suskalo Date: Fri, 15 Apr 2022 13:52:41 -0500 Subject: [PATCH 06/11] Update ffi namespace for jdk 18 --- src/clj/coffi/ffi.clj | 89 +++++++++++++++++++--------------- src/java/coffi/ffi/Loader.java | 4 +- 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/clj/coffi/ffi.clj b/src/clj/coffi/ffi.clj index 061ff3b..6b4016f 100644 --- a/src/clj/coffi/ffi.clj +++ b/src/clj/coffi/ffi.clj @@ -17,7 +17,9 @@ Addressable CLinker FunctionDescriptor + MemoryAddress MemoryLayout + NativeSymbol SegmentAllocator))) ;;; FFI Code loading and function access @@ -33,18 +35,9 @@ (Loader/loadLibrary (.getAbsolutePath (io/file path)))) (defn find-symbol - "Gets the [[MemoryAddress]] of a symbol from the loaded libraries." + "Gets the [[NativeSymbol]] of a symbol from the loaded libraries." [sym] - (let [sym (name sym)] - (Loader/findSymbol sym))) - -(defn- method-type - "Gets the [[MethodType]] for a set of `args` and `ret` types." - ([args] (method-type args ::mem/void)) - ([args ret] - (MethodType/methodType - ^Class (mem/java-layout ret) - ^"[Ljava.lang.Class;" (into-array Class (map mem/java-layout args))))) + (Loader/findSymbol (name sym))) (defn- function-descriptor "Gets the [[FunctionDescriptor]] for a set of `args` and `ret` types." @@ -60,8 +53,8 @@ (defn- downcall-handle "Gets the [[MethodHandle]] for the function at the `address`." - [address method-type function-descriptor] - (.downcallHandle (CLinker/getInstance) address method-type function-descriptor)) + [sym function-descriptor] + (.downcallHandle (CLinker/systemCLinker) sym function-descriptor)) (def ^:private load-instructions "Mapping from primitive types to the instruction used to load them onto the stack." @@ -138,6 +131,15 @@ [:invokevirtual (prim-classes prim-type) (unbox-fn-for-type prim-type) [prim]]] [])))) +(defn- coerce-addressable + "If the passed `type` is [[MemoryAddress]], returns [[Addressable]], otherwise returns `type`. + + This is used to declare the return types of upcall stubs." + [type] + (if (= type MemoryAddress) + Addressable + type)) + (defn- downcall-class "Class definition for an implementation of [[IFn]] which calls a closed over method handle without reflection, unboxing primitives when needed." @@ -174,7 +176,7 @@ args) [:invokevirtual MethodHandle "invokeExact" (cond->> - (conj (mapv insn-layout args) + (conj (mapv (comp coerce-addressable insn-layout) args) (insn-layout ret)) (not (mem/primitive-type ret)) (cons SegmentAllocator))] (to-object-asm ret) @@ -185,12 +187,12 @@ [handle args ret] (insn/new-instance (downcall-class args ret) ^MethodHandle handle)) -(defn- ensure-address +(defn- ensure-symbol "Gets the address if the argument is [[Addressable]], otherwise calls [[find-symbol]] on it." - [symbol-or-addr] - (if (instance? Addressable symbol-or-addr) - (mem/address-of symbol-or-addr) + ^NativeSymbol [symbol-or-addr] + (if (instance? NativeSymbol symbol-or-addr) + symbol-or-addr (find-symbol symbol-or-addr))) (defn make-downcall @@ -205,10 +207,8 @@ first argument of a [[SegmentAllocator]]." [symbol-or-addr args ret] (-> symbol-or-addr - ensure-address - (downcall-handle - (method-type args ret) - (function-descriptor args ret)) + ensure-symbol + (downcall-handle (function-descriptor args ret)) (downcall-fn args ret))) (defn make-varargs-factory @@ -440,7 +440,7 @@ arguments." [symbol required-args ret] (-> symbol - ensure-address + ensure-symbol (make-varargs-factory required-args ret) (make-serde-varargs-wrapper required-args ret))) @@ -452,7 +452,6 @@ ::mem/short :sreturn ::mem/int :ireturn ::mem/long :lreturn - ::mem/long-long :lreturn ::mem/char :creturn ::mem/float :freturn ::mem/double :dreturn @@ -460,7 +459,7 @@ (def ^:private double-sized? "Set of primitive types which require 2 indices in the constant pool." - #{::mem/double ::mem/long ::mem/long-long}) + #{::mem/double ::mem/long}) (defn- upcall-class "Constructs a class definition for a class with a single method, `upcall`, which @@ -482,7 +481,7 @@ {:name :upcall :flags #{:public} :desc (conj (mapv insn-layout arg-types) - (insn-layout ret-type)) + (coerce-addressable (insn-layout ret-type))) :emit [[:aload 0] [:getfield :this "upcall_ifn" IFn] (loop [types arg-types @@ -498,7 +497,7 @@ inc))) acc)) [:invokeinterface IFn "invoke" (repeat (inc (count arg-types)) Object)] - (to-prim-asm ret-type) + (to-prim-asm (coerce-addressable ret-type)) [(return-for-type ret-type :areturn)]]}]}) (defn- upcall @@ -506,6 +505,17 @@ [f arg-types ret-type] (insn/new-instance (upcall-class arg-types ret-type) ^IFn f)) +(defn- method-type + "Gets the [[MethodType]] for a set of `args` and `ret` types." + ([args] (method-type args ::mem/void)) + ([args ret] + (MethodType/methodType + ^Class (let [r (mem/java-layout ret)] + (if (= r MemoryAddress) + Addressable + r)) + ^"[Ljava.lang.Class;" (into-array Class (map mem/java-layout args))))) + (defn- upcall-handle "Constructs a method handle for invoking `f`, a function of `arg-count` args." [f arg-types ret-type] @@ -532,7 +542,7 @@ (defmethod mem/serialize* ::fn [f [_fn arg-types ret-type & {:keys [raw-fn?]}] scope] (.upcallStub - (CLinker/getInstance) + (CLinker/systemCLinker) (cond-> f (not raw-fn?) (upcall-serde-wrapper arg-types ret-type) :always (upcall-handle arg-types ret-type)) @@ -544,9 +554,8 @@ (when-not (mem/null? addr) (vary-meta (-> addr - (downcall-handle - (method-type arg-types ret-type) - (function-descriptor arg-types ret-type)) + (as-> addr (NativeSymbol/ofAddress "coffi_upcall_symbol" addr (mem/connected-scope))) + (downcall-handle (function-descriptor arg-types ret-type)) (downcall-fn arg-types ret-type) (cond-> (not raw-fn?) (make-serde-wrapper arg-types ret-type))) assoc ::address addr))) @@ -556,19 +565,16 @@ (defn const "Gets the value of a constant stored in `symbol-or-addr`." [symbol-or-addr type] - (mem/deserialize (ensure-address symbol-or-addr) [::mem/pointer type])) + (mem/deserialize (.address (ensure-symbol symbol-or-addr)) [::mem/pointer type])) -(deftype StaticVariable [addr type meta] - Addressable - (address [_] - addr) +(deftype StaticVariable [seg type meta] IDeref (deref [_] - (mem/deserialize addr [::mem/pointer type])) + (mem/deserialize seg type)) IObj (withMeta [_ meta-map] - (StaticVariable. addr type (atom meta-map))) + (StaticVariable. seg type (atom meta-map))) IMeta (meta [_] @meta) @@ -583,7 +589,7 @@ [^StaticVariable static-var newval] (mem/serialize-into newval (.-type static-var) - (mem/slice-global (.-addr static-var) (mem/size-of (.-type static-var))) + (.-seg static-var) (mem/global-scope)) newval) @@ -603,7 +609,10 @@ See [[freset!]], [[fswap!]]." [symbol-or-addr type] - (StaticVariable. (ensure-address symbol-or-addr) type (atom nil))) + (StaticVariable. (mem/as-segment (.address (ensure-symbol symbol-or-addr)) + (mem/size-of type) + (mem/global-scope)) + type (atom nil))) (s/def :coffi.ffi.symbolspec/symbol string?) (s/def :coffi.ffi.symbolspec/type keyword?) diff --git a/src/java/coffi/ffi/Loader.java b/src/java/coffi/ffi/Loader.java index b06d00f..9ad662f 100644 --- a/src/java/coffi/ffi/Loader.java +++ b/src/java/coffi/ffi/Loader.java @@ -36,8 +36,8 @@ public class Loader { * * @param symbol The name of the symbol to load from a library. */ - public static MemoryAddress findSymbol(String symbol) { - return CLinker.systemLookup().lookup(symbol) + public static NativeSymbol findSymbol(String symbol) { + return CLinker.systemCLinker().lookup(symbol) .orElseGet(() -> SymbolLookup.loaderLookup().lookup(symbol).orElse(null)); } } From 7d4f0e6567b78e51b85d3ab981bc6ea3077bba8e Mon Sep 17 00:00:00 2001 From: Joshua Suskalo Date: Thu, 7 Jul 2022 09:25:58 -0500 Subject: [PATCH 07/11] Update readme and changelog about removal of long-long --- CHANGELOG.md | 3 ++- README.md | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a0fd9f..4d7b30b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ All notable changes to this project will be documented in this file. This change ## [Unreleased] ### Removed -- `coffi.mem/slice-into` function no longer has an equivalent in panama, but see 2-arity of `coffi.mem/as-segment` for an alternative +- `:coffi.mem/long-long` primitive type +- `coffi.mem/slice-into`; the function no longer has an equivalent in panama, but see 2-arity of `coffi.mem/as-segment` for an alternative ### Changed - `coffi.mem/as-segment` no longer has a close action arity diff --git a/README.md b/README.md index ddd50a9..48e4e51 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,6 @@ Coffi defines a basic set of primitive types: - short - int - long -- long-long - char - float - double From a9e3ed090dbdd78d55a72e8f0faa7f88a8b1a025 Mon Sep 17 00:00:00 2001 From: Joshua Suskalo Date: Thu, 7 Jul 2022 09:45:04 -0500 Subject: [PATCH 08/11] Bump minor version --- build.clj | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.clj b/build.clj index 5c7e0b2..21c254b 100644 --- a/build.clj +++ b/build.clj @@ -17,7 +17,7 @@ [clojure.tools.build.api :as b])) (def lib-coord 'org.suskalo/coffi) -(def version (format "0.4.%s" (b/git-count-revs nil))) +(def version (format "0.5.%s" (b/git-count-revs nil))) (def resource-dirs ["resources/"]) diff --git a/pom.xml b/pom.xml index 8b013fd..d2a6a67 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 org.suskalo/coffi - A Foreign Function Interface in Clojure for JDK 17. + A Foreign Function Interface in Clojure for JDK 18. https://github.com/IGJoshua/coffi From f439135337140928a49d7a02e03a45a154069aed Mon Sep 17 00:00:00 2001 From: Joshua Suskalo Date: Thu, 7 Jul 2022 09:56:25 -0500 Subject: [PATCH 09/11] Update changelog for release --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d7b30b..a38b111 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Change Log All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). -## [Unreleased] +## [0.5.357] - 2022-07-07 ### Removed - `:coffi.mem/long-long` primitive type - `coffi.mem/slice-into`; the function no longer has an equivalent in panama, but see 2-arity of `coffi.mem/as-segment` for an alternative From e18a2e1246835d61fb7ae0a24fca30295a596658 Mon Sep 17 00:00:00 2001 From: Joshua Suskalo Date: Thu, 7 Jul 2022 09:56:31 -0500 Subject: [PATCH 10/11] Update codox documentation --- docs/coffi.ffi.html | 16 +++++----- docs/coffi.layout.html | 2 +- docs/coffi.mem.html | 72 ++++++++++++++++++++---------------------- docs/index.html | 2 +- 4 files changed, 45 insertions(+), 47 deletions(-) diff --git a/docs/coffi.ffi.html b/docs/coffi.ffi.html index 2d0f7c3..a8fea82 100644 --- a/docs/coffi.ffi.html +++ b/docs/coffi.ffi.html @@ -2,18 +2,18 @@ ""> coffi.ffi documentation

coffi.ffi

Functions for creating handles to native functions and loading native libraries.

cfn

(cfn symbol args ret)

Constructs a Clojure function to call the native function referenced by symbol.

The function returned will serialize any passed arguments into the args types, and deserialize the return to the ret type.

-

If your args and ret are constants, then it is more efficient to call make-downcall followed by make-serde-wrapper because the latter has an inline definition which will result in less overhead from serdes.

const

(const symbol-or-addr type)

Gets the value of a constant stored in symbol-or-addr.

defcfn

macro

(defcfn name docstring? attr-map? symbol arg-types ret-type)(defcfn name docstring? attr-map? symbol arg-types ret-type native-fn & fn-tail)

Defines a Clojure function which maps to a native function.

+

If your args and ret are constants, then it is more efficient to call make-downcall followed by make-serde-wrapper because the latter has an inline definition which will result in less overhead from serdes.

const

(const symbol-or-addr type)

Gets the value of a constant stored in symbol-or-addr.

defcfn

macro

(defcfn name docstring? attr-map? symbol arg-types ret-type)(defcfn name docstring? attr-map? symbol arg-types ret-type native-fn & fn-tail)

Defines a Clojure function which maps to a native function.

name is the symbol naming the resulting var. symbol is a symbol or string naming the library symbol to link against. arg-types is a vector of qualified keywords representing the argument types. ret-type is a single qualified keyword representing the return type. fn-tail is the body of the function (potentially with multiple arities) which wraps the native one. Inside the function, native-fn is bound to a function that will serialize its arguments, call the native function, and deserialize its return type. If any body is present, you must call this function in order to call the native code.

If no fn-tail is provided, then the resulting function will simply serialize the arguments according to arg-types, call the native function, and deserialize the return value.

The number of args in the fn-tail need not match the number of arg-types for the native function. It need only call the native wrapper function with the correct arguments.

-

See serialize, deserialize, make-downcall.

find-symbol

(find-symbol sym)

Gets the MemoryAddress of a symbol from the loaded libraries.

freset!

(freset! static-var newval)

Sets the value of static-var to newval, running it through serialize.

fswap!

(fswap! static-var f & args)

Non-atomically runs the function f over the value stored in static-var.

-

The value is deserialized before passing it to f, and serialized before putting the value into static-var.

load-library

(load-library path)

Loads the library at path.

load-system-library

(load-system-library libname)

Loads the library named libname from the system’s load path.

make-downcall

(make-downcall symbol-or-addr args ret)

Constructs a downcall function reference to symbol-or-addr with the given args and ret types.

+

See serialize, deserialize, make-downcall.

find-symbol

(find-symbol sym)

Gets the NativeSymbol of a symbol from the loaded libraries.

freset!

(freset! static-var newval)

Sets the value of static-var to newval, running it through serialize.

fswap!

(fswap! static-var f & args)

Non-atomically runs the function f over the value stored in static-var.

+

The value is deserialized before passing it to f, and serialized before putting the value into static-var.

load-library

(load-library path)

Loads the library at path.

load-system-library

(load-system-library libname)

Loads the library named libname from the system’s load path.

make-downcall

(make-downcall symbol-or-addr args ret)

Constructs a downcall function reference to symbol-or-addr with the given args and ret types.

The function returned takes only arguments whose types match exactly the java-layout for that type, and returns an argument with exactly the java-layout of the ret type. This function will perform no serialization or deserialization of arguments or the return type.

-

If the ret type is non-primitive, then the returned function will take a first argument of a SegmentAllocator.

make-serde-varargs-wrapper

(make-serde-varargs-wrapper varargs-factory required-args ret-type)

Constructs a wrapper function for the varargs-factory which produces functions that serialize the arguments and deserialize the return value.

make-serde-wrapper

(make-serde-wrapper downcall arg-types ret-type)

Constructs a wrapper function for the downcall which serializes the arguments and deserializes the return value.

make-varargs-factory

(make-varargs-factory symbol required-args ret)

Returns a function for constructing downcalls with additional types for arguments.

+

If the ret type is non-primitive, then the returned function will take a first argument of a SegmentAllocator.

make-serde-varargs-wrapper

(make-serde-varargs-wrapper varargs-factory required-args ret-type)

Constructs a wrapper function for the varargs-factory which produces functions that serialize the arguments and deserialize the return value.

make-serde-wrapper

(make-serde-wrapper downcall arg-types ret-type)

Constructs a wrapper function for the downcall which serializes the arguments and deserializes the return value.

make-varargs-factory

(make-varargs-factory symbol required-args ret)

Returns a function for constructing downcalls with additional types for arguments.

The required-args are the types of the first arguments passed to the downcall handle, and the values passed to the returned function are only the varargs types.

The returned function is memoized, so that only one downcall function will be generated per combination of argument types.

-

See make-downcall.

reify-libspec

(reify-libspec libspec)

Loads all the symbols specified in the libspec.

-

The value of each key of the passed map is transformed as by reify-symbolspec.

reify-symbolspec

multimethod

Takes a spec for a symbol reference and returns a live value for that type.

static-variable

(static-variable symbol-or-addr type)

Constructs a reference to a mutable value stored in symbol-or-addr.

+

See make-downcall.

reify-libspec

(reify-libspec libspec)

Loads all the symbols specified in the libspec.

+

The value of each key of the passed map is transformed as by reify-symbolspec.

reify-symbolspec

multimethod

Takes a spec for a symbol reference and returns a live value for that type.

static-variable

(static-variable symbol-or-addr type)

Constructs a reference to a mutable value stored in symbol-or-addr.

The returned value can be dereferenced, and has metadata, and the address of the value can be queried with address-of.

-

See freset!, fswap!.

vacfn-factory

(vacfn-factory symbol required-args ret)

Constructs a varargs factory to call the native function referenced by symbol.

-

The function returned takes any number of type arguments and returns a specialized Clojure function for calling the native function with those arguments.

\ No newline at end of file +

See freset!, fswap!.

vacfn-factory

(vacfn-factory symbol required-args ret)

Constructs a varargs factory to call the native function referenced by symbol.

+

The function returned takes any number of type arguments and returns a specialized Clojure function for calling the native function with those arguments.

\ No newline at end of file diff --git a/docs/coffi.layout.html b/docs/coffi.layout.html index 302f3c0..e5aca21 100644 --- a/docs/coffi.layout.html +++ b/docs/coffi.layout.html @@ -1,4 +1,4 @@ coffi.layout documentation

coffi.layout

Functions for adjusting the layout of structs.

with-c-layout

(with-c-layout struct-spec)

Forces a struct specification to C layout rules.

-

This will add padding fields between fields to match C alignment requirements.

\ No newline at end of file +

This will add padding fields between fields to match C alignment requirements.

\ No newline at end of file diff --git a/docs/coffi.mem.html b/docs/coffi.mem.html index 08465a6..207830a 100644 --- a/docs/coffi.mem.html +++ b/docs/coffi.mem.html @@ -1,51 +1,49 @@ -coffi.mem documentation

coffi.mem

Functions for managing native allocations, resource scopes, and (de)serialization.

+coffi.mem documentation

coffi.mem

Functions for managing native allocations, resource scopes, and (de)serialization.

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 segments.

-

When writing code that manipulates a segment, it’s best practice to use with-acquired on the segment-scope in order to ensure it won’t be released during its manipulation.

add-close-action!

(add-close-action! scope action)

Adds a 0-arity function to be run when the scope closes.

address-of

(address-of addressable)

Gets the address of a given segment.

-

This value can be used as an argument to functions which take a pointer.

address?

(address? addr)

Checks if an object is a memory address.

-

nil is considered an address.

align-of

(align-of type)

The alignment in bytes of the given type.

alloc

(alloc size)(alloc size scope)

Allocates size bytes.

-

If a scope is provided, the allocation will be reclaimed when it is closed.

alloc-instance

(alloc-instance type)(alloc-instance type scope)

Allocates a memory segment for the given type.

alloc-with

(alloc-with allocator size)(alloc-with allocator size alignment)

Allocates size bytes using the allocator.

as-segment

(as-segment address size scope)(as-segment address size scope cleanup)

Dereferences an address into a memory segment associated with the scope.

-

If cleanup is provided, it is a 0-arity function run when the scope is closed. This can be used to register a free method for the memory, or do other cleanup in a way that doesn’t require modifying the code at the point of freeing, and allows shared or garbage collected resources to be freed correctly.

big-endian

The big-endian ByteOrder.

-

See little-endian, native-endian.

byte-layout

c-layout

multimethod

Gets the layout object for a given type.

+

When writing code that manipulates a segment, it’s best practice to use with-acquired on the segment-scope in order to ensure it won’t be released during its manipulation.

add-close-action!

(add-close-action! scope action)

Adds a 0-arity function to be run when the scope closes.

address-of

(address-of addressable)

Gets the address of a given segment.

+

This value can be used as an argument to functions which take a pointer.

address?

(address? addr)

Checks if an object is a memory address.

+

nil is considered an address.

align-of

(align-of type)

The alignment in bytes of the given type.

alloc

(alloc size)(alloc size scope)

Allocates size bytes.

+

If a scope is provided, the allocation will be reclaimed when it is closed.

alloc-instance

(alloc-instance type)(alloc-instance type scope)

Allocates a memory segment for the given type.

alloc-with

(alloc-with allocator size)(alloc-with allocator size alignment)

Allocates size bytes using the allocator.

as-segment

(as-segment address size)(as-segment address size scope)

Dereferences an address into a memory segment associated with the scope.

big-endian

The big-endian ByteOrder.

+

See little-endian, native-endian.

byte-layout

c-layout

multimethod

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.

char-layout

The MemoryLayout for a c-sized char in native-endian ByteOrder.

clone-segment

(clone-segment segment)(clone-segment segment scope)

Clones the content of segment into a new segment of the same size.

connected-scope

(connected-scope)

Constructs a new scope to reclaim all connected resources at once.

+

Otherwise, it should return a GroupLayout for the given type.

char-layout

The MemoryLayout for a c-sized char in native-endian ByteOrder.

clone-segment

(clone-segment segment)(clone-segment segment scope)

Clones the content of segment into a new segment of the same size.

connected-scope

(connected-scope)

Constructs a new scope to reclaim all connected resources at once.

The scope 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.

-

This type of scope cannot be closed, and therefore should not be created in a with-open clause.

copy-segment

(copy-segment dest src)

Copies the content to dest from src.

-

Returns dest.

defalias

macro

(defalias new-type aliased-type)

Defines a type alias from new-type to aliased-type.

-

This creates needed serialization and deserialization implementations for the aliased type.

deserialize

(deserialize obj type)

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.

deserialize*

multimethod

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.

deserialize-from

multimethod

Deserializes the given segment into a Clojure data structure.

+

This type of scope cannot be closed, and therefore should not be created in a with-open clause.

copy-segment

(copy-segment dest src)

Copies the content to dest from src.

+

Returns dest.

defalias

macro

(defalias new-type aliased-type)

Defines a type alias from new-type to aliased-type.

+

This creates needed serialization and deserialization implementations for the aliased type.

deserialize

(deserialize obj type)

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.

deserialize*

multimethod

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.

deserialize-from

multimethod

Deserializes the given segment into a Clojure data structure.

For types that serialize to primitives, a default implementation will deserialize the primitive before calling deserialize*.

-

Implementations of this should be inside a with-acquired block for the the segment’s scope if they perform multiple memory operations.

double-alignment

The alignment in bytes of a c-sized double.

double-layout

The MemoryLayout for a c-sized double in native-endian ByteOrder.

double-size

The size in bytes of a c-sized double.

float-alignment

The alignment in bytes of a c-sized float.

float-layout

The MemoryLayout for a c-sized float in native-endian ByteOrder.

float-size

The size in bytes of a c-sized float.

global-scope

(global-scope)

Constructs the global scope, which will never reclaim its resources.

-

This scope 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.

int-alignment

The alignment in bytes of a c-sized int.

int-layout

The MemoryLayout for a c-sized int in native-endian ByteOrder.

int-size

The size in bytes of a c-sized int.

java-layout

(java-layout type)

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.

java-prim-layout

Map of primitive type names to the Java types for a method handle.

little-endian

The little-endian ByteOrder.

-

See big-endian, native-endian

long-alignment

The alignment in bytes of a c-sized long.

long-layout

The MemoryLayout for a c-sized long in native-endian ByteOrder.

long-long-alignment

The alignment in bytes of a c-sized long long.

long-long-layout

The MemoryLayout for a c-sized long-long in native-endian ByteOrder.

long-long-size

The size in bytes of a c-sized long long.

long-size

The size in bytes of a c-sized long.

native-endian

The ByteOrder for the native endianness of the current hardware.

-

See big-endian, little-endian.

null?

(null? addr)

Checks if a memory address is null.

pointer-alignment

The alignment in bytes of a c-sized pointer.

pointer-layout

The MemoryLayout for a native pointer in native-endian ByteOrder.

pointer-size

The size in bytes of a c-sized pointer.

primitive-type

multimethod

Gets the primitive type that is used to pass as an argument for the type.

+

Implementations of this should be inside a with-acquired block for the the segment’s scope if they perform multiple memory operations.

double-alignment

The alignment in bytes of a c-sized double.

double-layout

The MemoryLayout for a c-sized double in native-endian ByteOrder.

double-size

The size in bytes of a c-sized double.

float-alignment

The alignment in bytes of a c-sized float.

float-layout

The MemoryLayout for a c-sized float in native-endian ByteOrder.

float-size

The size in bytes of a c-sized float.

global-scope

(global-scope)

Constructs the global scope, which will never reclaim its resources.

+

This scope 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.

int-alignment

The alignment in bytes of a c-sized int.

int-layout

The MemoryLayout for a c-sized int in native-endian ByteOrder.

int-size

The size in bytes of a c-sized int.

java-layout

(java-layout type)

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.

java-prim-layout

Map of primitive type names to the Java types for a method handle.

little-endian

The little-endian ByteOrder.

+

See big-endian, native-endian

long-alignment

The alignment in bytes of a c-sized long.

long-layout

The MemoryLayout for a c-sized long in native-endian ByteOrder.

long-size

The size in bytes of a c-sized long.

native-endian

The ByteOrder for the native endianness of the current hardware.

+

See big-endian, little-endian.

null?

(null? addr)

Checks if a memory address is null.

pointer-alignment

The alignment in bytes of a c-sized pointer.

pointer-layout

The MemoryLayout for a native pointer in native-endian ByteOrder.

pointer-size

The size in bytes of a c-sized pointer.

primitive-type

multimethod

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.

Implementations of this method should take into account that type arguments may not always be evaluated before passing to this function.

-

Returns nil for any type which does not have a primitive representation.

primitive-types

A set of all primitive types.

primitive?

(primitive? type)

A predicate to determine if a given type is primitive.

read-address

(read-address segment)(read-address segment offset)

Reads a MemoryAddress from the segment, at an optional offset.

read-byte

(read-byte segment)(read-byte segment offset)

Reads a byte from the segment, at an optional offset.

read-char

(read-char segment)(read-char segment offset)

Reads a char from the segment, at an optional offset.

read-double

(read-double segment)(read-double segment offset)(read-double segment offset byte-order)

Reads a double from the segment, at an optional offset.

-

If byte-order is not provided, it defaults to native-endian.

read-float

(read-float segment)(read-float segment offset)(read-float segment offset byte-order)

Reads a float from the segment, at an optional offset.

-

If byte-order is not provided, it defaults to native-endian.

read-int

(read-int segment)(read-int segment offset)(read-int segment offset byte-order)

Reads a int from the segment, at an optional offset.

-

If byte-order is not provided, it defaults to native-endian.

read-long

(read-long segment)(read-long segment offset)(read-long segment offset byte-order)

Reads a long from the segment, at an optional offset.

-

If byte-order is not provided, it defaults to native-endian.

read-short

(read-short segment)(read-short segment offset)(read-short segment offset byte-order)

Reads a short from the segment, at an optional offset.

-

If byte-order is not provided, it defaults to native-endian.

scope-allocator

(scope-allocator scope)

Constructs a segment allocator from the given scope.

-

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.

segment-scope

(segment-scope segment)

Gets the scope used to construct the segment.

seq-of

(seq-of type segment)

Constructs a lazy sequence of type elements deserialized from segment.

serialize

(serialize obj type)(serialize obj type scope)

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.

serialize*

multimethod

Constructs a serialized version of the obj and returns it.

+

Returns nil for any type which does not have a primitive representation.

primitive-types

A set of all primitive types.

primitive?

(primitive? type)

A predicate to determine if a given type is primitive.

read-address

(read-address segment)(read-address segment offset)

Reads a MemoryAddress from the segment, at an optional offset.

read-byte

(read-byte segment)(read-byte segment offset)

Reads a byte from the segment, at an optional offset.

read-char

(read-char segment)(read-char segment offset)

Reads a char from the segment, at an optional offset.

read-double

(read-double segment)(read-double segment offset)(read-double segment offset byte-order)

Reads a double from the segment, at an optional offset.

+

If byte-order is not provided, it defaults to native-endian.

read-float

(read-float segment)(read-float segment offset)(read-float segment offset byte-order)

Reads a float from the segment, at an optional offset.

+

If byte-order is not provided, it defaults to native-endian.

read-int

(read-int segment)(read-int segment offset)(read-int segment offset byte-order)

Reads a int from the segment, at an optional offset.

+

If byte-order is not provided, it defaults to native-endian.

read-long

(read-long segment)(read-long segment offset)(read-long segment offset byte-order)

Reads a long from the segment, at an optional offset.

+

If byte-order is not provided, it defaults to native-endian.

read-short

(read-short segment)(read-short segment offset)(read-short segment offset byte-order)

Reads a short from the segment, at an optional offset.

+

If byte-order is not provided, it defaults to native-endian.

scope-allocator

(scope-allocator scope)

Constructs a segment allocator from the given scope.

+

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.

segment-scope

(segment-scope segment)

Gets the scope used to construct the segment.

seq-of

(seq-of type segment)

Constructs a lazy sequence of type elements deserialized from segment.

serialize

(serialize obj type)(serialize obj type scope)

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.

serialize*

multimethod

Constructs a serialized version of the obj and returns it.

Any new allocations made during the serialization should be tied to the given scope, except in extenuating circumstances.

-

This method should only be implemented for types that serialize to primitives.

serialize-into

multimethod

Writes a serialized version of the obj to the given segment.

+

This method should only be implemented for types that serialize to primitives.

serialize-into

multimethod

Writes a serialized version of the obj to the given segment.

Any new allocations made during the serialization should be tied to the given scope, except in extenuating circumstances.

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 the result value into the segment.

-

Implementations of this should be inside a with-acquired block for the scope if they perform multiple memory operations.

shared-scope

(shared-scope)

Constructs a new shared scope.

-

This scope can be shared across threads and memory allocated in it will only be cleaned up once every thread accessing the scope closes it.

short-alignment

The alignment in bytes of a c-sized short.

short-layout

The MemoryLayout for a c-sized short in native-endian ByteOrder.

short-size

The size in bytes of a c-sized short.

size-of

(size-of type)

The size in bytes of the given type.

slice

(slice segment offset)(slice segment offset size)

Get a slice over the segment with the given offset.

slice-global

(slice-global address size)

Gets a slice of the global address space.

-

Because this fetches from the global segment, it has no associated scope, and therefore the reference created here cannot prevent the value from being freed. Be careful to ensure that you are not retaining an object incorrectly.

slice-into

(slice-into address segment)(slice-into address segment size)

Get a slice into the segment starting at the address.

slice-segments

(slice-segments segment size)

Constructs a lazy seq of size-length memory segments, sliced from segment.

stack-scope

(stack-scope)

Constructs a new scope for use only in this thread.

-

The memory allocated within this scope is cheap to allocate, like a native stack.

with-acquired

macro

(with-acquired scopes & body)

Acquires one or more scopes until the body completes.

-

This is only necessary to do on shared scopes, however if you are operating on an arbitrary passed scope, it is best practice to wrap code that interacts with it wrapped in this.

with-offset

(with-offset address offset)

Get a new address offset from the old address.

write-address

(write-address segment value)(write-address segment offset value)

Writes a MemoryAddress to the segment, at an optional offset.

write-byte

(write-byte segment value)(write-byte segment offset value)

Writes a byte to the segment, at an optional offset.

write-char

(write-char segment value)(write-char segment offset value)

Writes a char to the segment, at an optional offset.

write-double

(write-double segment value)(write-double segment offset value)(write-double segment offset byte-order value)

Writes a double to the segment, at an optional offset.

-

If byte-order is not provided, it defaults to native-endian.

write-float

(write-float segment value)(write-float segment offset value)(write-float segment offset byte-order value)

Writes a float to the segment, at an optional offset.

-

If byte-order is not provided, it defaults to native-endian.

write-int

(write-int segment value)(write-int segment offset value)(write-int segment offset byte-order value)

Writes a int to the segment, at an optional offset.

-

If byte-order is not provided, it defaults to native-endian.

write-long

(write-long segment value)(write-long segment offset value)(write-long segment offset byte-order value)

Writes a long to the segment, at an optional offset.

-

If byte-order is not provided, it defaults to native-endian.

write-short

(write-short segment value)(write-short segment offset value)(write-short segment offset byte-order value)

Writes a short to the segment, at an optional offset.

-

If byte-order is not provided, it defaults to native-endian.

\ No newline at end of file +

Implementations of this should be inside a with-acquired block for the scope if they perform multiple memory operations.

shared-scope

(shared-scope)

Constructs a new shared scope.

+

This scope can be shared across threads and memory allocated in it will only be cleaned up once every thread accessing the scope closes it.

short-alignment

The alignment in bytes of a c-sized short.

short-layout

The MemoryLayout for a c-sized short in native-endian ByteOrder.

short-size

The size in bytes of a c-sized short.

size-of

(size-of type)

The size in bytes of the given type.

slice

(slice segment offset)(slice segment offset size)

Get a slice over the segment with the given offset.

slice-into

(slice-into address segment)(slice-into address segment size)

Get a slice into the segment starting at the address.

slice-segments

(slice-segments segment size)

Constructs a lazy seq of size-length memory segments, sliced from segment.

stack-scope

(stack-scope)

Constructs a new scope for use only in this thread.

+

The memory allocated within this scope is cheap to allocate, like a native stack.

with-acquired

macro

(with-acquired scopes & body)

Acquires one or more scopes until the body completes.

+

This is only necessary to do on shared scopes, however if you are operating on an arbitrary passed scope, it is best practice to wrap code that interacts with it wrapped in this.

with-offset

(with-offset address offset)

Get a new address offset from the old address.

write-address

(write-address segment value)(write-address segment offset value)

Writes a MemoryAddress to the segment, at an optional offset.

write-byte

(write-byte segment value)(write-byte segment offset value)

Writes a byte to the segment, at an optional offset.

write-char

(write-char segment value)(write-char segment offset value)

Writes a char to the segment, at an optional offset.

write-double

(write-double segment value)(write-double segment offset value)(write-double segment offset byte-order value)

Writes a double to the segment, at an optional offset.

+

If byte-order is not provided, it defaults to native-endian.

write-float

(write-float segment value)(write-float segment offset value)(write-float segment offset byte-order value)

Writes a float to the segment, at an optional offset.

+

If byte-order is not provided, it defaults to native-endian.

write-int

(write-int segment value)(write-int segment offset value)(write-int segment offset byte-order value)

Writes a int to the segment, at an optional offset.

+

If byte-order is not provided, it defaults to native-endian.

write-long

(write-long segment value)(write-long segment offset value)(write-long segment offset byte-order value)

Writes a long to the segment, at an optional offset.

+

If byte-order is not provided, it defaults to native-endian.

write-short

(write-short segment value)(write-short segment offset value)(write-short segment offset byte-order value)

Writes a short to the segment, at an optional offset.

+

If byte-order is not provided, it defaults to native-endian.

\ No newline at end of file diff --git a/docs/index.html b/docs/index.html index dcd979b..3967959 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,3 +1,3 @@ -coffi v0.4.341

coffi v0.4.341

A Foreign Function Interface in Clojure for JDK 17.

Namespaces

coffi.layout

Functions for adjusting the layout of structs.

Public variables and functions:

\ No newline at end of file +coffi v0.4.341

coffi v0.4.341

A Foreign Function Interface in Clojure for JDK 17.

Namespaces

coffi.layout

Functions for adjusting the layout of structs.

Public variables and functions:

\ No newline at end of file From 919a171d308c24081e37413052716fb65685a813 Mon Sep 17 00:00:00 2001 From: Joshua Suskalo Date: Thu, 7 Jul 2022 10:00:39 -0500 Subject: [PATCH 11/11] Update readme for new version and JDK 18 --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index c2b40c4..c682235 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Coffi is a foreign function interface library for Clojure, using the new [Project Panama](https://openjdk.java.net/projects/panama/) that's a part of the -incubator in Java 17. This allows calling native code directly from Clojure +incubator in Java 18. This allows calling native code directly from Clojure without the need for either Java or native code specific to the library, as e.g. the JNI does. Coffi focuses on ease of use, including functions and macros for creating wrappers to allow the resulting native functions to act just like @@ -16,8 +16,8 @@ This library is available on Clojars. Add one of the following entries to the `:deps` key of your `deps.edn`: ```clojure -org.suskalo/coffi {:mvn/version "0.4.341"} -io.github.IGJoshua/coffi {:git/tag "v0.4.341" :git/sha "09b8195"} +org.suskalo/coffi {:mvn/version "0.5.357"} +io.github.IGJoshua/coffi {:git/tag "v0.5.357" :git/sha "a9e3ed0"} ``` If you use this library as a git dependency, you will need to prepare the @@ -1107,12 +1107,12 @@ These features are planned for future releases. ### Future JDKs The purpose of coffi is to provide a wrapper for published versions of Project Panama, starting with JDK 17. As new JDKs are released, coffi will be ported to -the newer versions of Panama. When JDK 18 is released, a tag will be added to -mark the final release of coffi that is compatible with Java 17, as that is the -LTS release of the JDK. Development of new features and fixes as well as support -for new Panama idioms and features will continue with focus only on the latest -JDK. If a particular feature is not specific to the newer JDK, PRs backporting -it to versions of coffi supporting Java 17 will likely be accepted. +the newer versions of Panama. Version `0.4.341` is the last version compatible +with JDK 17. Bugfixes, and potential backports of newer coffi features may be +found on the `jdk17-lts` branch. Development of new features and fixes as well +as support for new Panama idioms and features will continue with focus only on +the latest JDK. If a particular feature is not specific to the newer JDK, PRs +backporting it to versions of coffi supporting Java 17 will likely be accepted. ### 1.0 Release Because the feature that coffi wraps in the JDK is an incubator feature (and