Add macros to ease creating static variable references

This commit is contained in:
Joshua Suskalo 2022-07-07 13:27:02 -05:00
parent 20956f2549
commit d7e0ced38b
No known key found for this signature in database
GPG key ID: 9B6BA586EFF1B9F0
3 changed files with 43 additions and 3 deletions

View file

@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This change
## [Unreleased]
### Added
- 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
## [0.5.357] - 2022-07-07

View file

@ -265,18 +265,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 +300,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

View file

@ -561,6 +561,25 @@
[symbol-or-addr type]
(mem/deserialize (.address (ensure-symbol symbol-or-addr)) [::mem/pointer type]))
(s/def ::defconst-args
(s/cat :var-name simple-symbol?
:docstring (s/? string?)
:symbol-or-addr any?
:type ::mem/type))
(defmacro defconst
"Defines a var named by `symbol` to be the value of the given `type` from `symbol-or-addr`."
{:arglists '([symbol docstring? symbol-or-addr type])}
[& args]
(let [args (s/conform ::defconst-args args)]
`(let [symbol# (ensure-symbol ~(:symbol-or-addr args))]
(def ~(:var-name args)
~@(when-let [doc (:docstring args)]
(list doc))
(const symbol# ~(:type args))))))
(s/fdef defconst
:args ::defconst-args)
(deftype StaticVariable [seg type meta]
IDeref
(deref [_]
@ -615,6 +634,19 @@
(mem/global-scope))
type (atom nil)))
(defmacro defvar
"Defines a var named by `symbol` to be a reference to the native memory from `symbol-or-addr`."
{:arglists '([symbol docstring? symbol-or-addr type])}
[& args]
(let [args (s/conform ::defconst-args args)]
`(let [symbol# (ensure-symbol ~(:symbol-or-addr args))]
(def ~(:var-name args)
~@(when-let [doc (:docstring args)]
(list doc))
(static-variable symbol#)))))
(s/fdef defvar
:args ::defconst-args)
(s/def :coffi.ffi.symbolspec/symbol string?)
(s/def :coffi.ffi.symbolspec/type keyword?)
(s/def ::symbolspec