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] ## [Unreleased]
### Added ### 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 - 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 ## [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 ### Global Variables
Some libraries include global variables or constants accessible through symbols. 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 ```clojure
(def some-const (ffi/const "some_const" ::mem/int)) (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 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 value. If you need to refer to a global variable, then `static-variable` (or
used to create a reference to the native value. parallel `defvar`) can be used to create a reference to the native value.
```clojure ```clojure
(def some-var (ffi/static-variable "some_var" ::mem/int)) (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 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 A parallel function `fswap!` is also provided, but it does not provide any
atomic semantics either. 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 ### Complex Wrappers
Some functions require more complex code to map nicely to a Clojure function. 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 The `defcfn` macro provides facilities to wrap the native function with some

View file

@ -561,6 +561,25 @@
[symbol-or-addr type] [symbol-or-addr type]
(mem/deserialize (.address (ensure-symbol symbol-or-addr)) [::mem/pointer 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] (deftype StaticVariable [seg type meta]
IDeref IDeref
(deref [_] (deref [_]
@ -615,6 +634,19 @@
(mem/global-scope)) (mem/global-scope))
type (atom nil))) 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/symbol string?)
(s/def :coffi.ffi.symbolspec/type keyword?) (s/def :coffi.ffi.symbolspec/type keyword?)
(s/def ::symbolspec (s/def ::symbolspec