diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4a7671a..34ec353 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,23 @@
# 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/).
+## [0.6.409] - 2023-03-31
+### Added
+- Support for JDK 19
+- New macros for defining vars with values from native code
+- New function to allow getting the backing memory segment of a `coffi.ffi.StaticVariable`, to replace the `Addressable` implementation lost in the migration to JDK 18
+
+### Fixed
+- Bug where `static-variable`s with primitive types would not deserialize properly on `deref`
+- Uses of `defvar` not compiling
+- Bug where nil values would not be correctly coerced to null pointers when passed to inlined functions
+- Bug where inline serde functions would fail on complex pointer types
+- Bug where padding in structs may be increased when fields have alignments less than their size
+- Bug where pointer alignment was incorrectly defined
+
+### Changed
+- References to `scope` as a term have been changed to `session` to match Panama messaging. Where this conflicts with function names, old versions have been deprecated and new names have been introduced.
+
## [0.5.357] - 2022-07-07
### Removed
- `:coffi.mem/long-long` primitive type
@@ -100,6 +117,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
+[0.6.409]: https://github.com/IGJoshua/coffi/compare/v0.5.357...v0.6.409
[0.5.357]: https://github.com/IGJoshua/coffi/compare/v0.4.341...v0.5.357
[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
diff --git a/README.md b/README.md
index c682235..908748e 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 18. This allows calling native code directly from Clojure
+preview in Java 19. 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.5.357"}
-io.github.IGJoshua/coffi {:git/tag "v0.5.357" :git/sha "a9e3ed0"}
+org.suskalo/coffi {:mvn/version "0.6.409"}
+io.github.IGJoshua/coffi {:git/tag "v0.6.409" :git/sha "f974446"}
```
If you use this library as a git dependency, you will need to prepare the
@@ -27,19 +27,19 @@ library.
$ clj -X:deps prep
```
-Coffi requires usage of the module `jdk.incubator.foreign`, which means that the
-JVM must enable the usage of this module. In order to use coffi, add the
-following JVM arguments to your application.
+Coffi requires usage of the package `java.lang.foreign`, and everything in this
+package is considered to be a preview release, which are disabled by default. In
+order to use coffi, add the following JVM arguments to your application.
```sh
---add-modules=jdk.incubator.foreign --enable-native-access=ALL-UNNAMED
+--enable-preview --enable-native-access=ALL-UNNAMED
```
You can specify JVM arguments in a particular invocation of the Clojure CLI with
the -J flag like so:
``` sh
-clj -J--add-modules=jdk.incubator.foreign -J--enable-native-access=ALL-UNNAMED
+clj -J--enable-preview -J--enable-native-access=ALL-UNNAMED
```
You can also specify them in an alias in your `deps.edn` file under the
@@ -47,7 +47,7 @@ You can also specify them in an alias in your `deps.edn` file under the
using `-M`, `-A`, or `-X`.
``` clojure
-{:aliases {:dev {:jvm-opts ["--add-modules=jdk.incubator.foreign" "--enable-native-access=ALL-UNNAMED"]}}}
+{:aliases {:dev {:jvm-opts ["--enable-preview" "--enable-native-access=ALL-UNNAMED"]}}}
```
Other build tools should provide similar functionality if you check their
@@ -132,14 +132,13 @@ Coffi defines a basic set of primitive types:
Each of these types maps to their C counterpart. Values of any of these
primitive types except for `pointer` will be cast with their corresponding
-Clojure function (with `long-long` mapping to the `long` function) when they are
-passed as arguments to native functions. Additionally, the `c-string` type is
-defined, although it is not primitive.
+Clojure function when they are passed as arguments to native functions.
+Additionally, the `c-string` type is defined, although it is not primitive.
### Composite Types
In addition, some composite types are also defined in coffi, including struct
and union types (unions will be discussed with serialization and
-deserialization). For an example c struct and function:
+deserialization). For an example C struct and function:
```c
typedef struct point {
@@ -239,6 +238,23 @@ type and message in the registers section, but it's important to be aware of all
the same. Ideally you should test your callbacks before actually passing them to
native code.
+When writing a wrapper library for a C library, it may be a good choice to wrap
+all passed Clojure functions in an additional function which catches all
+throwables, potentially notifies the user in some manner (e.g. logging), and
+returns a default value. This is on the wrapper library's developer to decide
+when and where this is appropriate, as in some cases no reasonable default
+return value can be determined and it is most sensible to simply crash the JVM.
+This is the reason that coffi defaults to this behavior, as in the author's
+opinion it is better to fail hard and fast rather than to attempt to produce a
+default and cause unexpected behavior later.
+
+Another important thing to keep in mind is the expected lifetime of the function
+that you pass to native code. For example it is perfectly fine to pass an
+anonymous function to a native function if the callback will never be called
+again once the native function returns. If however it saves the callback for
+later use the JVM may collect it prematurely, causing a crash when the callback
+is later called by native code.
+
### Variadic Functions
Some native functions can take any number of arguments, and in these cases coffi
provides `vacfn-factory` (for "varargs C function factory").
@@ -265,18 +281,21 @@ does not support va-list, however it is a planned feature.
### Global Variables
Some libraries include global variables or constants accessible through symbols.
-To start with, constant values stored in symbols can be fetched with `const`
+To start with, constant values stored in symbols can be fetched with `const`, or
+the parallel macro `defconst`
```clojure
(def some-const (ffi/const "some_const" ::mem/int))
+(ffi/defconst some-const "some_const" ::mem/int)
```
This value is fetched once when you call `const` and is turned into a Clojure
-value. If you need to refer to a global variable, then `static-variable` can be
-used to create a reference to the native value.
+value. If you need to refer to a global variable, then `static-variable` (or
+parallel `defvar`) can be used to create a reference to the native value.
```clojure
(def some-var (ffi/static-variable "some_var" ::mem/int))
+(ffi/defvar some-var "some_var" ::mem/int)
```
This variable is an `IDeref`. Each time you dereference it, the value will be
@@ -297,6 +316,10 @@ value is being mutated on another thread.
A parallel function `fswap!` is also provided, but it does not provide any
atomic semantics either.
+The memory that backs the static variable can be fetched with the function
+`static-variable-segment`, which can be used to pass a pointer to the static
+variable to native functions that require it.
+
### Complex Wrappers
Some functions require more complex code to map nicely to a Clojure function.
The `defcfn` macro provides facilities to wrap the native function with some
@@ -331,29 +354,33 @@ This can be used to implement out variables often seen in native code.
(deserialize int-ptr [::mem/pointer ::mem/int])))
```
-### Scopes
+### Sessions
+**Before JDK 19 Sessions were called Scopes. Coffi retains functions that are
+named for creating scopes for backwards compatibility, but they will be removed
+in version 1.0.**
+
In order to serialize any non-primitive type (such as the previous
`[::mem/pointer ::mem/int]`), off-heap memory needs to be allocated. When memory
-is allocated inside the JVM, the memory is associated with a scope. Because none
-was provided here, the scope is an implicit scope, and the memory will be freed
-when the serialized object is garbage collected.
+is allocated inside the JVM, the memory is associated with a session. Because
+none was provided here, the session is an implicit session, and the memory will
+be freed when the serialized object is garbage collected.
In many cases this is not desirable, because the memory is not freed in a
deterministic manner, causing garbage collection pauses to become longer, as
-well as changing allocation performance. Instead of an implicit scope, there are
-other kinds of scopes as well. A `stack-scope` is a thread-local scope. Stack
-scopes are `Closeable`, which means they should usually be used in a `with-open`
-form. When a `stack-scope` is closed, it immediately frees all the memory
-associated with it. The previous example, `out-int`, can be implemented with a
-stack scope.
+well as changing allocation performance. Instead of an implicit session, there
+are other kinds of sessions as well. A `stack-session` is a thread-local
+session. Stack sessions are `Closeable`, which means they should usually be used
+in a `with-open` form. When a `stack-session` is closed, it immediately frees
+all the memory associated with it. The previous example, `out-int`, can be
+implemented with a stack session.
```clojure
(defcfn out-int
"out_int" [::mem/pointer] ::mem/void
native-fn
[i]
- (with-open [scope (mem/stack-scope)]
- (let [int-ptr (mem/serialize i [::mem/pointer ::mem/int] scope)]
+ (with-open [session (mem/stack-session)]
+ (let [int-ptr (mem/serialize i [::mem/pointer ::mem/int] session)]
(native-fn int-ptr)
(mem/deserialize int-ptr [::mem/pointer ::mem/int]))))
```
@@ -361,14 +388,15 @@ stack scope.
This will free the pointer immediately upon leaving the function.
When memory needs to be accessible from multiple threads, there's
-`shared-scope`. When using a `shared-scope`, it should be accessed inside a
-`with-acquired` block. When a `shared-scope` is `.close`d, it will release all
+`shared-session`. When using a `shared-session`, it should be accessed inside a
+`with-acquired` block. When a `shared-session` is `.close`d, it will release all
its associated memory when every `with-acquired` block associated with it is
exited.
-In addition, two non-`Closeable` scopes are `global-scope`, which never frees
-the resources associated with it, and `connected-scope`, which is a scope that
-frees its resources on garbage collection, like an implicit scope.
+In addition, two non-`Closeable` sessions are `global-session`, which never
+frees the resources associated with it, and `connected-session`, which is a
+session that frees its resources on garbage collection, like an implicit
+session.
### Serialization and Deserialization
Custom serializers and deserializers may also be created. This is done using two
@@ -398,8 +426,8 @@ serialize to primitives.
```clojure
(defmethod mem/serialize* ::vector
- [obj _type scope]
- (mem/address-of (mem/serialize obj [::mem/array ::mem/float 3] scope)))
+ [obj _type session]
+ (mem/address-of (mem/serialize obj [::mem/array ::mem/float 3] session)))
(defmethod mem/deserialize* ::vector
[addr _type]
@@ -408,9 +436,9 @@ serialize to primitives.
```
The `slice-global` function allows you to take an address without an associated
-scope and get a memory segment which can be deserialized.
+session and get a memory segment which can be deserialized.
-In cases like this where we don't know the scope of the pointer, we could use
+In cases like this where we don't know the session of the pointer, we could use
`add-close-action!` to ensure it's freed. For example if a `free-vector!`
function that takes a pointer exists, we could use this:
@@ -418,14 +446,14 @@ function that takes a pointer exists, we could use this:
(defcfn returns-vector
"returns_vector" [] ::mem/pointer
native-fn
- [scope]
+ [session]
(let [ret-ptr (native-fn)]
- (add-close-action! scope #(free-vector! ret-ptr))
+ (add-close-action! session #(free-vector! ret-ptr))
(deserialize ret-ptr ::vector)))
```
-This function takes a scope and returns the deserialized vector, and it will
-free the pointer when the scope closes.
+This function takes a session and returns the deserialized vector, and it will
+free the pointer when the session closes.
#### Tagged Union
For the tagged union type, we will represent the value as a vector of a keyword
@@ -477,7 +505,7 @@ deserialize the value into and out of memory segments. This is accomplished with
(map first))))
(defmethod mem/serialize-into ::tagged-union
- [obj [_tagged-union tags type-map] segment scope]
+ [obj [_tagged-union tags type-map] segment session]
(mem/serialize-into
{:tag (item-index tags (first obj))
:value (second obj)}
@@ -485,7 +513,7 @@ deserialize the value into and out of memory segments. This is accomplished with
[[:tag ::mem/long]
[:value (get type-map (first obj))]]]
segment
- scope))
+ session))
```
This serialization method is rather simple, it just turns the vector value into
@@ -542,7 +570,7 @@ it could be represented for serialization purposes like so:
This union however would not include the tag when serialized.
If a union is deserialized, then all that coffi does is to allocate a new
-segment of the appropriate size with an implicit scope so that it may later be
+segment of the appropriate size with an implicit session so that it may later be
garbage collected, and copies the data from the source segment into it. It's up
to the user to call `deserialize-from` on that segment with the appropriate
type.
@@ -567,12 +595,12 @@ With raw handles, the argument types are expected to exactly match the types
expected by the native function. For primitive types, those are primitives. For
addresses, that is `MemoryAddress`, and for composite types like structs and
unions, that is `MemorySegment`. Both `MemoryAddress` and `MemorySegment` come
-from the `jdk.incubator.foreign` package.
+from the `java.lang.foreign` package.
In addition, when a raw handle returns a composite type represented with a
`MemorySegment`, it requires an additional first argument, a `SegmentAllocator`,
-which can be acquired with `scope-allocator` to get one associated with a
-specific scope. The returned value will live until that scope is released.
+which can be acquired with `session-allocator` to get one associated with a
+specific session. The returned value will live until that session is released.
In addition, function types can be specified as being raw, in the following
manner:
@@ -612,8 +640,8 @@ floats, the following code might be used.
(defn returns-float-array
[]
- (with-open [scope (mem/stack-scope)]
- (let [out-floats (mem/alloc mem/pointer-size scope)
+ (with-open [session (mem/stack-session)]
+ (let [out-floats (mem/alloc mem/pointer-size session)
num-floats (function-handle (mem/address-of out-floats))
floats-addr (mem/read-address out-floats)
floats-slice (mem/slice-global floats-addr (unchecked-multiply-int mem/float-size num-floats))]
@@ -712,6 +740,8 @@ appealing, as they have a smaller API surface area and it's easier to wrap
functions.
### Benchmarks
+**BENCHMARKS FOR COFFI AND DTYPE-NEXT ARE BASED ON AN OLD VERSION. NEW BENCHMARKS WILL BE CREATED WHEN PANAMA COMES OUT OF PREVIEW**
+
An additional consideration when thinking about alternatives is the performance
of each available option. It's an established fact that JNA (used by all three
alternative libraries on JDK <16) introduces more overhead when calling native
@@ -954,8 +984,6 @@ coming from, but I'll admit that I haven't looked at their implementations very
closely.
#### dtype-next
-**BENCHMARKS FOR DTYPE-NEXT ARE BASED ON AN OLD VERSION. NEW BENCHMARKS WILL BE COMING SHORTLY**
-
The library dtype-next replaced tech.jna in the toolkit of the group working on
machine learning and array-based programming, and it includes support for
composite data types including structs, as well as primitive functions and
@@ -1089,7 +1117,10 @@ stands, coffi is the fastest FFI available to Clojure developers.
The project author is aware of these issues and plans to fix them in a future
release:
-There are currently no known issues! Hooray!
+- On M1 Macs occasional crashes are present when returning structs by value from
+ native code. At the moment this appears to be an upstream issue with Panama,
+ and will be reported once a minimal reproduction case with only Panama is
+ produced.
## Future Plans
These features are planned for future releases.
@@ -1097,27 +1128,26 @@ These features are planned for future releases.
- Support for va_args type
- 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
+- Helper macros for custom serde implementations for composite data types
### 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. 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.
+with JDK 17. Version `0.5.357` is the last version compatible with JDK 18.
+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
-likely in JDK 19 a [preview
-feature](https://mail.openjdk.java.net/pipermail/panama-dev/2021-September/014946.html))
+Because the feature that coffi wraps in the JDK is in preview as of JDK 19,
coffi itself will not be released in a 1.0.x version until the feature becomes a
core part of the JDK, likely before or during the next LTS release, Java 21, in
September 2023.
diff --git a/build.clj b/build.clj
index 21c254b..bdbf2ba 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.5.%s" (b/git-count-revs nil)))
+(def version (format "0.6.%s" (b/git-count-revs nil)))
(def resource-dirs ["resources/"])
@@ -49,11 +49,11 @@
"Compiles java classes required for interop."
[opts]
(.mkdirs (io/file class-dir))
- (b/process {:command-args ["javac" "--add-modules=jdk.incubator.foreign"
+ (b/process {:command-args ["javac" "--enable-preview"
"src/java/coffi/ffi/Loader.java"
"-d" class-dir
- "-target" "18"
- "-source" "18"]})
+ "-target" "19"
+ "-source" "19"]})
opts)
(defn- write-pom
diff --git a/deps.edn b/deps.edn
index 298cdeb..d0e1469 100644
--- a/deps.edn
+++ b/deps.edn
@@ -1,5 +1,5 @@
{:paths ["src/clj" "target/classes" "resources"]
- :deps {org.clojure/clojure {:mvn/version "1.10.3"}
+ :deps {org.clojure/clojure {:mvn/version "1.11.1"}
insn/insn {:mvn/version "0.2.1"}}
:deps/prep-lib {:alias :build
@@ -12,26 +12,26 @@
nodisassemble/nodisassemble {:mvn/version "0.1.3"}}
;; NOTE(Joshua): If you want to use nodisassemble you should also add a
;; -javaagent for the resolved location
- :jvm-opts ["--add-modules=jdk.incubator.foreign" "--enable-native-access=ALL-UNNAMED"]}
+ :jvm-opts ["--enable-native-access=ALL-UNNAMED" "--enable-preview"]}
:test {:extra-paths ["test/clj"]
:extra-deps {org.clojure/test.check {:mvn/version "1.1.0"}
io.github.cognitect-labs/test-runner
{:git/url "https://github.com/cognitect-labs/test-runner"
:sha "62ef1de18e076903374306060ac0e8a752e57c86"}}
- :jvm-opts ["--add-modules=jdk.incubator.foreign" "--enable-native-access=ALL-UNNAMED"]
+ :jvm-opts ["--enable-native-access=ALL-UNNAMED" "--enable-preview"]
:exec-fn cognitect.test-runner.api/test}
:codox {:extra-deps {codox/codox {:mvn/version "0.10.7"}}
:exec-fn codox.main/generate-docs
:exec-args {:name "coffi"
- :version "v0.5.357"
- :description "A Foreign Function Interface in Clojure for JDK 18."
+ :version "v0.6.409"
+ :description "A Foreign Function Interface in Clojure for JDK 19."
:source-paths ["src/clj"]
:output-path "docs"
:source-uri "https://github.com/IGJoshua/coffi/blob/{git-commit}/{filepath}#L{line}"
:metadata {:doc/format :markdown}}
- :jvm-opts ["--add-modules=jdk.incubator.foreign"
- "--add-opens" "java.base/java.lang=ALL-UNNAMED"]}
+ :jvm-opts ["--add-opens" "java.base/java.lang=ALL-UNNAMED"
+ "--enable-preview"]}
:build {:replace-deps {org.clojure/clojure {:mvn/version "1.10.3"}
io.github.clojure/tools.build {:git/tag "v0.3.0" :git/sha "e418fc9"}}
diff --git a/docs/coffi.ffi.html b/docs/coffi.ffi.html
index ac3e8c1..fe8810e 100644
--- a/docs/coffi.ffi.html
+++ b/docs/coffi.ffi.html
@@ -1,19 +1,20 @@
-
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.
(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.
(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.
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.
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.
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.
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.
Functions for managing native allocations, memory sessions, 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.
When writing code that manipulates a segment, it’s best practice to use with-acquired on the segment-session in order to ensure it won’t be released during its manipulation.
add-close-action!
(add-close-action! session action)
Adds a 0-arity function to be run when the session closes.
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.
For types which have a primitive representation, this deserializes the primitive representation. For types which do not, this deserializes out of a segment.
Constructs a new memory session to reclaim all connected resources at once.
+
The session 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 session cannot be closed, and therefore should not be created in a with-open clause.
For types which have a primitive representation, this deserializes the primitive representation. For types which do not, this deserializes out of a segment.
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.
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.
Constructs the global session, which will never reclaim its resources.
+
This session 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.
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.
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.
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.
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.
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.
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.
Constructs a segment allocator from the given session.
+
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.
Acquires one or more sessions until the body completes.
+
This is only necessary to do on shared sessions, however if you are operating on an arbitrary passed session, it is best practice to wrap code that interacts with it wrapped in this.