Rename scope to session everywhere
This commit is contained in:
parent
3838c0f13c
commit
49bdca0766
2 changed files with 176 additions and 125 deletions
|
|
@ -244,20 +244,20 @@
|
||||||
The return type and any arguments that are primitives will not
|
The return type and any arguments that are primitives will not
|
||||||
be (de)serialized except to be cast. If all arguments and return are
|
be (de)serialized except to be cast. If all arguments and return are
|
||||||
primitive, the `downcall` is returned directly. In cases where arguments must
|
primitive, the `downcall` is returned directly. In cases where arguments must
|
||||||
be serialized, a new [[mem/stack-scope]] is generated."
|
be serialized, a new [[mem/stack-session]] is generated."
|
||||||
[downcall arg-types ret-type]
|
[downcall arg-types ret-type]
|
||||||
(let [;; Complexity of types
|
(let [;; Complexity of types
|
||||||
const-args? (or (vector? arg-types) (nil? arg-types))
|
const-args? (or (vector? arg-types) (nil? arg-types))
|
||||||
simple-args? (when const-args?
|
simple-args? (when const-args?
|
||||||
(and (every? mem/primitive? arg-types)
|
(and (every? mem/primitive? arg-types)
|
||||||
;; NOTE(Joshua): Pointer types with serdes (e.g. [::mem/pointer ::mem/int])
|
;; NOTE(Joshua): Pointer types with serdes (e.g. [::mem/pointer ::mem/int])
|
||||||
;; still require a scope, making them not qualify as "simple".
|
;; still require a session, making them not qualify as "simple".
|
||||||
(every? keyword? (filter (comp #{::mem/pointer} mem/primitive-type) arg-types))))
|
(every? keyword? (filter (comp #{::mem/pointer} mem/primitive-type) arg-types))))
|
||||||
const-ret? (s/valid? ::mem/type ret-type)
|
const-ret? (s/valid? ::mem/type ret-type)
|
||||||
primitive-ret? (and const-ret?
|
primitive-ret? (and const-ret?
|
||||||
(or (and (mem/primitive? ret-type)
|
(or (and (mem/primitive? ret-type)
|
||||||
;; NOTE(Joshua): Pointer types with serdes require deserializing the
|
;; NOTE(Joshua): Pointer types with serdes require deserializing the
|
||||||
;; return value, but don't require passing a scope to the downcall,
|
;; return value, but don't require passing a session to the downcall,
|
||||||
;; making them cause the return to not be primitive, but it may still
|
;; making them cause the return to not be primitive, but it may still
|
||||||
;; be "simple".
|
;; be "simple".
|
||||||
(or (keyword? ret-type) (not (#{::mem/pointer} (mem/primitive-type ret-type)))))
|
(or (keyword? ret-type) (not (#{::mem/pointer} (mem/primitive-type ret-type)))))
|
||||||
|
|
@ -273,7 +273,7 @@
|
||||||
~ret-type
|
~ret-type
|
||||||
downcall#)
|
downcall#)
|
||||||
(let [;; All our symbols
|
(let [;; All our symbols
|
||||||
scope (gensym "scope")
|
session (gensym "session")
|
||||||
downcall-sym (gensym "downcall")
|
downcall-sym (gensym "downcall")
|
||||||
args-sym (when-not const-args?
|
args-sym (when-not const-args?
|
||||||
(gensym "args"))
|
(gensym "args"))
|
||||||
|
|
@ -292,7 +292,7 @@
|
||||||
(some->>
|
(some->>
|
||||||
(cond
|
(cond
|
||||||
(not (s/valid? ::mem/type type))
|
(not (s/valid? ::mem/type type))
|
||||||
`(mem/serialize ~sym ~type-sym ~scope)
|
`(mem/serialize ~sym ~type-sym ~session)
|
||||||
|
|
||||||
(and (mem/primitive? type)
|
(and (mem/primitive? type)
|
||||||
(not (#{::mem/pointer} (mem/primitive-type type))))
|
(not (#{::mem/pointer} (mem/primitive-type type))))
|
||||||
|
|
@ -303,11 +303,11 @@
|
||||||
`(or ~sym (MemoryAddress/NULL))
|
`(or ~sym (MemoryAddress/NULL))
|
||||||
|
|
||||||
(mem/primitive-type type)
|
(mem/primitive-type type)
|
||||||
`(mem/serialize* ~sym ~type-sym ~scope)
|
`(mem/serialize* ~sym ~type-sym ~session)
|
||||||
|
|
||||||
:else
|
:else
|
||||||
`(let [alloc# (mem/alloc-instance ~type-sym)]
|
`(let [alloc# (mem/alloc-instance ~type-sym)]
|
||||||
(mem/serialize-into ~sym ~type-sym alloc# ~scope)
|
(mem/serialize-into ~sym ~type-sym alloc# ~session)
|
||||||
alloc#))
|
alloc#))
|
||||||
(list sym)))
|
(list sym)))
|
||||||
|
|
||||||
|
|
@ -334,7 +334,7 @@
|
||||||
|
|
||||||
:else
|
:else
|
||||||
`(let [~args-sym (map (fn [obj# type#]
|
`(let [~args-sym (map (fn [obj# type#]
|
||||||
(mem/serialize obj# type# ~scope))
|
(mem/serialize obj# type# ~session))
|
||||||
~args-sym ~args-types-sym)]
|
~args-sym ~args-types-sym)]
|
||||||
~expr)))
|
~expr)))
|
||||||
|
|
||||||
|
|
@ -343,7 +343,7 @@
|
||||||
;; taking restargs, and so the downcall must be applied
|
;; taking restargs, and so the downcall must be applied
|
||||||
(-> `(~@(when (symbol? args) [`apply])
|
(-> `(~@(when (symbol? args) [`apply])
|
||||||
~downcall-sym
|
~downcall-sym
|
||||||
~@(when allocator? [`(mem/scope-allocator ~scope)])
|
~@(when allocator? [`(mem/session-allocator ~session)])
|
||||||
~@(if (symbol? args)
|
~@(if (symbol? args)
|
||||||
[args]
|
[args]
|
||||||
args))
|
args))
|
||||||
|
|
@ -366,12 +366,12 @@
|
||||||
:else
|
:else
|
||||||
(deserialize-segment expr)))
|
(deserialize-segment expr)))
|
||||||
|
|
||||||
wrap-scope (fn [expr]
|
wrap-session (fn [expr]
|
||||||
`(with-open [~scope (mem/stack-scope)]
|
`(with-open [~session (mem/stack-session)]
|
||||||
~expr))
|
~expr))
|
||||||
wrap-fn (fn [call needs-scope?]
|
wrap-fn (fn [call needs-session?]
|
||||||
`(fn [~@(if const-args? arg-syms ['& args-sym])]
|
`(fn [~@(if const-args? arg-syms ['& args-sym])]
|
||||||
~(cond-> call needs-scope? wrap-scope)))]
|
~(cond-> call needs-session? wrap-session)))]
|
||||||
`(let [;; NOTE(Joshua): To ensure all arguments are evaluated once and
|
`(let [;; NOTE(Joshua): To ensure all arguments are evaluated once and
|
||||||
;; in-order, they must be bound here
|
;; in-order, they must be bound here
|
||||||
~downcall-sym ~downcall
|
~downcall-sym ~downcall
|
||||||
|
|
@ -403,15 +403,15 @@
|
||||||
[downcall arg-types ret-type]
|
[downcall arg-types ret-type]
|
||||||
(if (mem/primitive-type ret-type)
|
(if (mem/primitive-type ret-type)
|
||||||
(fn native-fn [& args]
|
(fn native-fn [& args]
|
||||||
(with-open [scope (mem/stack-scope)]
|
(with-open [session (mem/stack-session)]
|
||||||
(mem/deserialize*
|
(mem/deserialize*
|
||||||
(apply downcall (map #(mem/serialize %1 %2 scope) args arg-types))
|
(apply downcall (map #(mem/serialize %1 %2 session) args arg-types))
|
||||||
ret-type)))
|
ret-type)))
|
||||||
(fn native-fn [& args]
|
(fn native-fn [& args]
|
||||||
(with-open [scope (mem/stack-scope)]
|
(with-open [session (mem/stack-session)]
|
||||||
(mem/deserialize-from
|
(mem/deserialize-from
|
||||||
(apply downcall (mem/scope-allocator scope)
|
(apply downcall (mem/session-allocator session)
|
||||||
(map #(mem/serialize %1 %2 scope) args arg-types))
|
(map #(mem/serialize %1 %2 session) args arg-types))
|
||||||
ret-type)))))
|
ret-type)))))
|
||||||
|
|
||||||
(defn make-serde-varargs-wrapper
|
(defn make-serde-varargs-wrapper
|
||||||
|
|
@ -536,30 +536,30 @@
|
||||||
|
|
||||||
(defn- upcall-serde-wrapper
|
(defn- upcall-serde-wrapper
|
||||||
"Creates a function that wraps `f` which deserializes the arguments and
|
"Creates a function that wraps `f` which deserializes the arguments and
|
||||||
serializes the return type in the [[global-scope]]."
|
serializes the return type in the [[global-session]]."
|
||||||
[f arg-types ret-type]
|
[f arg-types ret-type]
|
||||||
(fn [& args]
|
(fn [& args]
|
||||||
(mem/serialize
|
(mem/serialize
|
||||||
(apply f (map mem/deserialize args arg-types))
|
(apply f (map mem/deserialize args arg-types))
|
||||||
ret-type
|
ret-type
|
||||||
(mem/global-scope))))
|
(mem/global-session))))
|
||||||
|
|
||||||
(defmethod mem/serialize* ::fn
|
(defmethod mem/serialize* ::fn
|
||||||
[f [_fn arg-types ret-type & {:keys [raw-fn?]}] scope]
|
[f [_fn arg-types ret-type & {:keys [raw-fn?]}] session]
|
||||||
(.upcallStub
|
(.upcallStub
|
||||||
(Linker/nativeLinker)
|
(Linker/nativeLinker)
|
||||||
(cond-> f
|
(cond-> f
|
||||||
(not raw-fn?) (upcall-serde-wrapper arg-types ret-type)
|
(not raw-fn?) (upcall-serde-wrapper arg-types ret-type)
|
||||||
:always (upcall-handle arg-types ret-type))
|
:always (upcall-handle arg-types ret-type))
|
||||||
(function-descriptor arg-types ret-type)
|
(function-descriptor arg-types ret-type)
|
||||||
scope))
|
session))
|
||||||
|
|
||||||
(defmethod mem/deserialize* ::fn
|
(defmethod mem/deserialize* ::fn
|
||||||
[addr [_fn arg-types ret-type & {:keys [raw-fn?]}]]
|
[addr [_fn arg-types ret-type & {:keys [raw-fn?]}]]
|
||||||
(when-not (mem/null? addr)
|
(when-not (mem/null? addr)
|
||||||
(vary-meta
|
(vary-meta
|
||||||
(-> addr
|
(-> addr
|
||||||
(MemorySegment/ofAddress mem/pointer-size (mem/connected-scope))
|
(MemorySegment/ofAddress mem/pointer-size (mem/connected-session))
|
||||||
(downcall-handle (function-descriptor arg-types ret-type))
|
(downcall-handle (function-descriptor arg-types ret-type))
|
||||||
(downcall-fn arg-types ret-type)
|
(downcall-fn arg-types ret-type)
|
||||||
(cond-> (not raw-fn?) (make-serde-wrapper arg-types ret-type)))
|
(cond-> (not raw-fn?) (make-serde-wrapper arg-types ret-type)))
|
||||||
|
|
@ -614,7 +614,7 @@
|
||||||
(mem/serialize-into
|
(mem/serialize-into
|
||||||
newval (.-type static-var)
|
newval (.-type static-var)
|
||||||
(.-seg static-var)
|
(.-seg static-var)
|
||||||
(mem/global-scope))
|
(mem/global-session))
|
||||||
newval)
|
newval)
|
||||||
|
|
||||||
(defn fswap!
|
(defn fswap!
|
||||||
|
|
@ -642,7 +642,7 @@
|
||||||
[symbol-or-addr type]
|
[symbol-or-addr type]
|
||||||
(StaticVariable. (mem/as-segment (.address (ensure-symbol symbol-or-addr))
|
(StaticVariable. (mem/as-segment (.address (ensure-symbol symbol-or-addr))
|
||||||
(mem/size-of type)
|
(mem/size-of type)
|
||||||
(mem/global-scope))
|
(mem/global-session))
|
||||||
type (atom nil)))
|
type (atom nil)))
|
||||||
|
|
||||||
(defmacro defvar
|
(defmacro defvar
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(ns coffi.mem
|
(ns coffi.mem
|
||||||
"Functions for managing native allocations, resource scopes, and (de)serialization.
|
"Functions for managing native allocations, memory sessions, and (de)serialization.
|
||||||
|
|
||||||
For any new type to be implemented, three multimethods must be overriden, but
|
For any new type to be implemented, three multimethods must be overriden, but
|
||||||
which three depends on the native representation of the type.
|
which three depends on the native representation of the type.
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
segments.
|
segments.
|
||||||
|
|
||||||
When writing code that manipulates a segment, it's best practice to
|
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
|
use [[with-acquired]] on the [[segment-session]] in order to ensure it won't be
|
||||||
released during its manipulation."
|
released during its manipulation."
|
||||||
(:require
|
(:require
|
||||||
[clojure.set :as set]
|
[clojure.set :as set]
|
||||||
|
|
@ -42,23 +42,50 @@
|
||||||
|
|
||||||
(set! *warn-on-reflection* true)
|
(set! *warn-on-reflection* true)
|
||||||
|
|
||||||
(defn stack-scope
|
(defn stack-session
|
||||||
|
"Constructs a new session for use only in this thread.
|
||||||
|
|
||||||
|
The memory allocated within this session is cheap to allocate, like a native
|
||||||
|
stack."
|
||||||
|
^MemorySession []
|
||||||
|
(MemorySession/openConfined))
|
||||||
|
|
||||||
|
(defn ^:deprecated stack-scope
|
||||||
"Constructs a new scope for use only in this thread.
|
"Constructs a new scope for use only in this thread.
|
||||||
|
|
||||||
The memory allocated within this scope is cheap to allocate, like a native
|
The memory allocated within this scope is cheap to allocate, like a native
|
||||||
stack."
|
stack."
|
||||||
^MemorySession []
|
^MemorySession []
|
||||||
(MemorySession/openConfined))
|
(stack-session))
|
||||||
|
|
||||||
(defn shared-scope
|
(defn shared-session
|
||||||
|
"Constructs a new shared memory session.
|
||||||
|
|
||||||
|
This session can be shared across threads and memory allocated in it will only
|
||||||
|
be cleaned up once every thread accessing the session closes it."
|
||||||
|
^MemorySession []
|
||||||
|
(MemorySession/openShared))
|
||||||
|
|
||||||
|
(defn ^:deprecated shared-scope
|
||||||
"Constructs a new shared scope.
|
"Constructs a new shared scope.
|
||||||
|
|
||||||
This scope can be shared across threads and memory allocated in it will only
|
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."
|
be cleaned up once every thread accessing the scope closes it."
|
||||||
^MemorySession []
|
^MemorySession []
|
||||||
(MemorySession/openShared))
|
(shared-session))
|
||||||
|
|
||||||
(defn connected-scope
|
(defn connected-session
|
||||||
|
"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."
|
||||||
|
^MemorySession []
|
||||||
|
(MemorySession/openImplicit))
|
||||||
|
|
||||||
|
(defn ^:deprecated connected-scope
|
||||||
"Constructs a new scope to reclaim all connected resources at once.
|
"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
|
The scope may be shared across threads, and all resources created with it will
|
||||||
|
|
@ -67,9 +94,19 @@
|
||||||
This type of scope cannot be closed, and therefore should not be created in
|
This type of scope cannot be closed, and therefore should not be created in
|
||||||
a [[with-open]] clause."
|
a [[with-open]] clause."
|
||||||
^MemorySession []
|
^MemorySession []
|
||||||
(MemorySession/openImplicit))
|
(connected-session))
|
||||||
|
|
||||||
(defn global-scope
|
(defn global-session
|
||||||
|
"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."
|
||||||
|
^MemorySession []
|
||||||
|
(MemorySession/global))
|
||||||
|
|
||||||
|
(defn ^:deprecated global-scope
|
||||||
"Constructs the global scope, which will never reclaim its resources.
|
"Constructs the global scope, which will never reclaim its resources.
|
||||||
|
|
||||||
This scope may be shared across threads, but is intended mainly in cases where
|
This scope may be shared across threads, but is intended mainly in cases where
|
||||||
|
|
@ -77,29 +114,43 @@
|
||||||
management is relinquished to a native library, such as when returned from a
|
management is relinquished to a native library, such as when returned from a
|
||||||
callback."
|
callback."
|
||||||
^MemorySession []
|
^MemorySession []
|
||||||
(MemorySession/global))
|
(global-session))
|
||||||
|
|
||||||
(defn scope-allocator
|
(defn session-allocator
|
||||||
|
"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."
|
||||||
|
^SegmentAllocator [^MemorySession session]
|
||||||
|
(SegmentAllocator/newNativeArena session))
|
||||||
|
|
||||||
|
(defn ^:deprecated scope-allocator
|
||||||
"Constructs a segment allocator from the given `scope`.
|
"Constructs a segment allocator from the given `scope`.
|
||||||
|
|
||||||
This is primarily used when working with unwrapped downcall functions. When a
|
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
|
downcall function returns a non-primitive type, it must be provided with an
|
||||||
allocator."
|
allocator."
|
||||||
^SegmentAllocator [^MemorySession scope]
|
^SegmentAllocator [^MemorySession scope]
|
||||||
(SegmentAllocator/newNativeArena scope))
|
(session-allocator scope))
|
||||||
|
|
||||||
(defn segment-scope
|
(defn segment-session
|
||||||
"Gets the scope used to construct the `segment`."
|
"Gets the memory session used to construct the `segment`."
|
||||||
^MemorySession [segment]
|
^MemorySession [segment]
|
||||||
(.session ^MemorySegment segment))
|
(.session ^MemorySegment segment))
|
||||||
|
|
||||||
|
(defn ^:deprecated segment-scope
|
||||||
|
"Gets the scope used to construct the `segment`."
|
||||||
|
^MemorySession [segment]
|
||||||
|
(segment-session segment))
|
||||||
|
|
||||||
(defn alloc
|
(defn alloc
|
||||||
"Allocates `size` bytes.
|
"Allocates `size` bytes.
|
||||||
|
|
||||||
If a `scope` is provided, the allocation will be reclaimed when it is closed."
|
If a `session` is provided, the allocation will be reclaimed when it is closed."
|
||||||
(^MemorySegment [size] (alloc size (connected-scope)))
|
(^MemorySegment [size] (alloc size (connected-session)))
|
||||||
(^MemorySegment [size scope] (MemorySegment/allocateNative (long size) ^MemorySession scope))
|
(^MemorySegment [size session] (MemorySegment/allocateNative (long size) ^MemorySession session))
|
||||||
(^MemorySegment [size alignment scope] (MemorySegment/allocateNative (long size) (long alignment) ^MemorySession scope)))
|
(^MemorySegment [size alignment session] (MemorySegment/allocateNative (long size) (long alignment) ^MemorySession session)))
|
||||||
|
|
||||||
(defn alloc-with
|
(defn alloc-with
|
||||||
"Allocates `size` bytes using the `allocator`."
|
"Allocates `size` bytes using the `allocator`."
|
||||||
|
|
@ -109,23 +160,23 @@
|
||||||
(.allocate ^SegmentAllocator allocator (long size) (long alignment))))
|
(.allocate ^SegmentAllocator allocator (long size) (long alignment))))
|
||||||
|
|
||||||
(defmacro with-acquired
|
(defmacro with-acquired
|
||||||
"Acquires one or more `scopes` until the `body` completes.
|
"Acquires one or more `sessions` until the `body` completes.
|
||||||
|
|
||||||
This is only necessary to do on shared scopes, however if you are operating on
|
This is only necessary to do on shared sessions, however if you are operating
|
||||||
an arbitrary passed scope, it is best practice to wrap code that interacts
|
on an arbitrary passed session, it is best practice to wrap code that
|
||||||
with it wrapped in this."
|
interacts with it wrapped in this."
|
||||||
{:style/indent 1}
|
{:style/indent 1}
|
||||||
[scopes & body]
|
[sessions & body]
|
||||||
(if (seq scopes)
|
(if (seq sessions)
|
||||||
`(let [scope# ~(first scopes)]
|
`(let [session# ~(first sessions)]
|
||||||
(.whileAlive
|
(.whileAlive
|
||||||
^MemorySession scope#
|
^MemorySession session#
|
||||||
(^:once fn* []
|
(^:once fn* []
|
||||||
(with-acquired [~@(rest scopes)]
|
(with-acquired [~@(rest sessions)]
|
||||||
~@body))))
|
~@body))))
|
||||||
`(do ~@body)))
|
`(do ~@body)))
|
||||||
(s/fdef with-acquired
|
(s/fdef with-acquired
|
||||||
:args (s/cat :scopes any?
|
:args (s/cat :sessions any?
|
||||||
:body (s/* any?)))
|
:body (s/* any?)))
|
||||||
|
|
||||||
(defn address-of
|
(defn address-of
|
||||||
|
|
@ -167,33 +218,33 @@
|
||||||
(.addOffset ^MemoryAddress address (long offset)))
|
(.addOffset ^MemoryAddress address (long offset)))
|
||||||
|
|
||||||
(defn add-close-action!
|
(defn add-close-action!
|
||||||
"Adds a 0-arity function to be run when the `scope` closes."
|
"Adds a 0-arity function to be run when the `session` closes."
|
||||||
[^MemorySession scope ^Runnable action]
|
[^MemorySession session ^Runnable action]
|
||||||
(.addCloseAction scope action)
|
(.addCloseAction session action)
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
(defn as-segment
|
(defn as-segment
|
||||||
"Dereferences an `address` into a memory segment associated with the `scope`."
|
"Dereferences an `address` into a memory segment associated with the `session`."
|
||||||
(^MemorySegment [^MemoryAddress address size]
|
(^MemorySegment [^MemoryAddress address size]
|
||||||
(MemorySegment/ofAddress address (long size) (connected-scope)))
|
(MemorySegment/ofAddress address (long size) (connected-session)))
|
||||||
(^MemorySegment [^MemoryAddress address size scope]
|
(^MemorySegment [^MemoryAddress address size session]
|
||||||
(MemorySegment/ofAddress address (long size) scope)))
|
(MemorySegment/ofAddress address (long size) session)))
|
||||||
|
|
||||||
(defn copy-segment
|
(defn copy-segment
|
||||||
"Copies the content to `dest` from `src`.
|
"Copies the content to `dest` from `src`.
|
||||||
|
|
||||||
Returns `dest`."
|
Returns `dest`."
|
||||||
^MemorySegment [^MemorySegment dest ^MemorySegment src]
|
^MemorySegment [^MemorySegment dest ^MemorySegment src]
|
||||||
(with-acquired (map segment-scope [src dest])
|
(with-acquired (map segment-session [src dest])
|
||||||
(.copyFrom dest src)
|
(.copyFrom dest src)
|
||||||
dest))
|
dest))
|
||||||
|
|
||||||
(defn clone-segment
|
(defn clone-segment
|
||||||
"Clones the content of `segment` into a new segment of the same size."
|
"Clones the content of `segment` into a new segment of the same size."
|
||||||
(^MemorySegment [segment] (clone-segment segment (connected-scope)))
|
(^MemorySegment [segment] (clone-segment segment (connected-session)))
|
||||||
(^MemorySegment [^MemorySegment segment scope]
|
(^MemorySegment [^MemorySegment segment session]
|
||||||
(with-acquired [(segment-scope segment) scope]
|
(with-acquired [(segment-session segment) session]
|
||||||
(copy-segment ^MemorySegment (alloc (.byteSize segment) scope) segment))))
|
(copy-segment ^MemorySegment (alloc (.byteSize segment) session) segment))))
|
||||||
|
|
||||||
(defn slice-segments
|
(defn slice-segments
|
||||||
"Constructs a lazy seq of `size`-length memory segments, sliced from `segment`."
|
"Constructs a lazy seq of `size`-length memory segments, sliced from `segment`."
|
||||||
|
|
@ -835,8 +886,8 @@
|
||||||
|
|
||||||
(defn alloc-instance
|
(defn alloc-instance
|
||||||
"Allocates a memory segment for the given `type`."
|
"Allocates a memory segment for the given `type`."
|
||||||
(^MemorySegment [type] (alloc-instance type (connected-scope)))
|
(^MemorySegment [type] (alloc-instance type (connected-session)))
|
||||||
(^MemorySegment [type scope] (MemorySegment/allocateNative ^long (size-of type) ^MemorySession scope)))
|
(^MemorySegment [type session] (MemorySegment/allocateNative ^long (size-of type) ^MemorySession session)))
|
||||||
|
|
||||||
(declare serialize serialize-into)
|
(declare serialize serialize-into)
|
||||||
|
|
||||||
|
|
@ -844,68 +895,68 @@
|
||||||
"Constructs a serialized version of the `obj` and returns it.
|
"Constructs a serialized version of the `obj` and returns it.
|
||||||
|
|
||||||
Any new allocations made during the serialization should be tied to the given
|
Any new allocations made during the serialization should be tied to the given
|
||||||
`scope`, except in extenuating circumstances.
|
`session`, except in extenuating circumstances.
|
||||||
|
|
||||||
This method should only be implemented for types that serialize to primitives."
|
This method should only be implemented for types that serialize to primitives."
|
||||||
(fn
|
(fn
|
||||||
#_{:clj-kondo/ignore [:unused-binding]}
|
#_{:clj-kondo/ignore [:unused-binding]}
|
||||||
[obj type scope]
|
[obj type session]
|
||||||
(type-dispatch type)))
|
(type-dispatch type)))
|
||||||
|
|
||||||
(defmethod serialize* :default
|
(defmethod serialize* :default
|
||||||
[obj type _scope]
|
[obj type _session]
|
||||||
(throw (ex-info "Attempted to serialize a non-primitive type with primitive methods"
|
(throw (ex-info "Attempted to serialize a non-primitive type with primitive methods"
|
||||||
{:type type
|
{:type type
|
||||||
:object obj})))
|
:object obj})))
|
||||||
|
|
||||||
(defmethod serialize* ::byte
|
(defmethod serialize* ::byte
|
||||||
[obj _type _scope]
|
[obj _type _session]
|
||||||
(byte obj))
|
(byte obj))
|
||||||
|
|
||||||
(defmethod serialize* ::short
|
(defmethod serialize* ::short
|
||||||
[obj _type _scope]
|
[obj _type _session]
|
||||||
(short obj))
|
(short obj))
|
||||||
|
|
||||||
(defmethod serialize* ::int
|
(defmethod serialize* ::int
|
||||||
[obj _type _scope]
|
[obj _type _session]
|
||||||
(int obj))
|
(int obj))
|
||||||
|
|
||||||
(defmethod serialize* ::long
|
(defmethod serialize* ::long
|
||||||
[obj _type _scope]
|
[obj _type _session]
|
||||||
(long obj))
|
(long obj))
|
||||||
|
|
||||||
(defmethod serialize* ::char
|
(defmethod serialize* ::char
|
||||||
[obj _type _scope]
|
[obj _type _session]
|
||||||
(char obj))
|
(char obj))
|
||||||
|
|
||||||
(defmethod serialize* ::float
|
(defmethod serialize* ::float
|
||||||
[obj _type _scope]
|
[obj _type _session]
|
||||||
(float obj))
|
(float obj))
|
||||||
|
|
||||||
(defmethod serialize* ::double
|
(defmethod serialize* ::double
|
||||||
[obj _type _scope]
|
[obj _type _session]
|
||||||
(double obj))
|
(double obj))
|
||||||
|
|
||||||
(defmethod serialize* ::pointer
|
(defmethod serialize* ::pointer
|
||||||
[obj type scope]
|
[obj type session]
|
||||||
(if-not (null? obj)
|
(if-not (null? obj)
|
||||||
(if (sequential? type)
|
(if (sequential? type)
|
||||||
(with-acquired [scope]
|
(with-acquired [session]
|
||||||
(let [segment (alloc-instance (second type) scope)]
|
(let [segment (alloc-instance (second type) session)]
|
||||||
(serialize-into obj (second type) segment scope)
|
(serialize-into obj (second type) segment session)
|
||||||
(address-of segment)))
|
(address-of segment)))
|
||||||
obj)
|
obj)
|
||||||
(MemoryAddress/NULL)))
|
(MemoryAddress/NULL)))
|
||||||
|
|
||||||
(defmethod serialize* ::void
|
(defmethod serialize* ::void
|
||||||
[_obj _type _scope]
|
[_obj _type _session]
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
(defmulti serialize-into
|
(defmulti serialize-into
|
||||||
"Writes a serialized version of the `obj` to the given `segment`.
|
"Writes a serialized version of the `obj` to the given `segment`.
|
||||||
|
|
||||||
Any new allocations made during the serialization should be tied to the given
|
Any new allocations made during the serialization should be tied to the given
|
||||||
`scope`, except in extenuating circumstances.
|
`session`, except in extenuating circumstances.
|
||||||
|
|
||||||
This method should be implemented for any type which does not
|
This method should be implemented for any type which does not
|
||||||
override [[c-layout]].
|
override [[c-layout]].
|
||||||
|
|
@ -914,66 +965,66 @@
|
||||||
the result value into the `segment`.
|
the result value into the `segment`.
|
||||||
|
|
||||||
Implementations of this should be inside a [[with-acquired]] block for the
|
Implementations of this should be inside a [[with-acquired]] block for the
|
||||||
`scope` if they perform multiple memory operations."
|
`session` if they perform multiple memory operations."
|
||||||
(fn
|
(fn
|
||||||
#_{:clj-kondo/ignore [:unused-binding]}
|
#_{:clj-kondo/ignore [:unused-binding]}
|
||||||
[obj type segment scope]
|
[obj type segment session]
|
||||||
(type-dispatch type)))
|
(type-dispatch type)))
|
||||||
|
|
||||||
(defmethod serialize-into :default
|
(defmethod serialize-into :default
|
||||||
[obj type segment scope]
|
[obj type segment session]
|
||||||
(if-some [prim-layout (primitive-type type)]
|
(if-some [prim-layout (primitive-type type)]
|
||||||
(with-acquired [(segment-scope segment) scope]
|
(with-acquired [(segment-session segment) session]
|
||||||
(serialize-into (serialize* obj type scope) prim-layout segment scope))
|
(serialize-into (serialize* obj type session) prim-layout segment session))
|
||||||
(throw (ex-info "Attempted to serialize an object to a type that has not been overriden"
|
(throw (ex-info "Attempted to serialize an object to a type that has not been overriden"
|
||||||
{:type type
|
{:type type
|
||||||
:object obj}))))
|
:object obj}))))
|
||||||
|
|
||||||
(defmethod serialize-into ::byte
|
(defmethod serialize-into ::byte
|
||||||
[obj _type segment _scope]
|
[obj _type segment _session]
|
||||||
(write-byte segment (byte obj)))
|
(write-byte segment (byte obj)))
|
||||||
|
|
||||||
(defmethod serialize-into ::short
|
(defmethod serialize-into ::short
|
||||||
[obj type segment _scope]
|
[obj type segment _session]
|
||||||
(if (sequential? type)
|
(if (sequential? type)
|
||||||
(write-short segment 0 (second type) (short obj))
|
(write-short segment 0 (second type) (short obj))
|
||||||
(write-short segment (short obj))))
|
(write-short segment (short obj))))
|
||||||
|
|
||||||
(defmethod serialize-into ::int
|
(defmethod serialize-into ::int
|
||||||
[obj type segment _scope]
|
[obj type segment _session]
|
||||||
(if (sequential? type)
|
(if (sequential? type)
|
||||||
(write-int segment 0 (second type) (int obj))
|
(write-int segment 0 (second type) (int obj))
|
||||||
(write-int segment (int obj))))
|
(write-int segment (int obj))))
|
||||||
|
|
||||||
(defmethod serialize-into ::long
|
(defmethod serialize-into ::long
|
||||||
[obj type segment _scope]
|
[obj type segment _session]
|
||||||
(if (sequential? type)
|
(if (sequential? type)
|
||||||
(write-long segment 0 (second type) (long obj))
|
(write-long segment 0 (second type) (long obj))
|
||||||
(write-long segment (long obj))))
|
(write-long segment (long obj))))
|
||||||
|
|
||||||
(defmethod serialize-into ::char
|
(defmethod serialize-into ::char
|
||||||
[obj _type segment _scope]
|
[obj _type segment _session]
|
||||||
(write-char segment (char obj)))
|
(write-char segment (char obj)))
|
||||||
|
|
||||||
(defmethod serialize-into ::float
|
(defmethod serialize-into ::float
|
||||||
[obj type segment _scope]
|
[obj type segment _session]
|
||||||
(if (sequential? type)
|
(if (sequential? type)
|
||||||
(write-float segment 0 (second type) (float obj))
|
(write-float segment 0 (second type) (float obj))
|
||||||
(write-float segment (float obj))))
|
(write-float segment (float obj))))
|
||||||
|
|
||||||
(defmethod serialize-into ::double
|
(defmethod serialize-into ::double
|
||||||
[obj type segment _scope]
|
[obj type segment _session]
|
||||||
(if (sequential? type)
|
(if (sequential? type)
|
||||||
(write-double segment 0 (second type) (double obj))
|
(write-double segment 0 (second type) (double obj))
|
||||||
(write-double segment (double obj))))
|
(write-double segment (double obj))))
|
||||||
|
|
||||||
(defmethod serialize-into ::pointer
|
(defmethod serialize-into ::pointer
|
||||||
[obj type segment scope]
|
[obj type segment session]
|
||||||
(with-acquired [(segment-scope segment) scope]
|
(with-acquired [(segment-session segment) session]
|
||||||
(write-address
|
(write-address
|
||||||
segment
|
segment
|
||||||
(cond-> obj
|
(cond-> obj
|
||||||
(sequential? type) (serialize* type scope)))))
|
(sequential? type) (serialize* type session)))))
|
||||||
|
|
||||||
(defn serialize
|
(defn serialize
|
||||||
"Serializes an arbitrary type.
|
"Serializes an arbitrary type.
|
||||||
|
|
@ -981,12 +1032,12 @@
|
||||||
For types which have a primitive representation, this serializes into that
|
For types which have a primitive representation, this serializes into that
|
||||||
representation. For types which do not, it allocates a new segment and
|
representation. For types which do not, it allocates a new segment and
|
||||||
serializes into that."
|
serializes into that."
|
||||||
([obj type] (serialize obj type (connected-scope)))
|
([obj type] (serialize obj type (connected-session)))
|
||||||
([obj type scope]
|
([obj type session]
|
||||||
(if (primitive-type type)
|
(if (primitive-type type)
|
||||||
(serialize* obj type scope)
|
(serialize* obj type session)
|
||||||
(let [segment (alloc-instance type scope)]
|
(let [segment (alloc-instance type session)]
|
||||||
(serialize-into obj type segment scope)
|
(serialize-into obj type segment session)
|
||||||
segment))))
|
segment))))
|
||||||
|
|
||||||
(declare deserialize deserialize*)
|
(declare deserialize deserialize*)
|
||||||
|
|
@ -998,7 +1049,7 @@
|
||||||
deserialize the primitive before calling [[deserialize*]].
|
deserialize the primitive before calling [[deserialize*]].
|
||||||
|
|
||||||
Implementations of this should be inside a [[with-acquired]] block for the the
|
Implementations of this should be inside a [[with-acquired]] block for the the
|
||||||
`segment`'s scope if they perform multiple memory operations."
|
`segment`'s session if they perform multiple memory operations."
|
||||||
(fn
|
(fn
|
||||||
#_{:clj-kondo/ignore [:unused-binding]}
|
#_{:clj-kondo/ignore [:unused-binding]}
|
||||||
[segment type]
|
[segment type]
|
||||||
|
|
@ -1054,7 +1105,7 @@
|
||||||
|
|
||||||
(defmethod deserialize-from ::pointer
|
(defmethod deserialize-from ::pointer
|
||||||
[segment type]
|
[segment type]
|
||||||
(with-acquired [(segment-scope segment)]
|
(with-acquired [(segment-session segment)]
|
||||||
(cond-> (read-address segment)
|
(cond-> (read-address segment)
|
||||||
(sequential? type) (deserialize* type))))
|
(sequential? type) (deserialize* type))))
|
||||||
|
|
||||||
|
|
@ -1129,7 +1180,7 @@
|
||||||
(defn seq-of
|
(defn seq-of
|
||||||
"Constructs a lazy sequence of `type` elements deserialized from `segment`."
|
"Constructs a lazy sequence of `type` elements deserialized from `segment`."
|
||||||
[type segment]
|
[type segment]
|
||||||
(with-acquired [(segment-scope segment)]
|
(with-acquired [(segment-session segment)]
|
||||||
(map #(deserialize % type) (slice-segments segment (size-of type)))))
|
(map #(deserialize % type) (slice-segments segment (size-of type)))))
|
||||||
|
|
||||||
;;; Raw composite types
|
;;; Raw composite types
|
||||||
|
|
@ -1141,7 +1192,7 @@
|
||||||
(c-layout type))
|
(c-layout type))
|
||||||
|
|
||||||
(defmethod serialize-into ::raw
|
(defmethod serialize-into ::raw
|
||||||
[obj _type segment _scope]
|
[obj _type segment _session]
|
||||||
(copy-segment segment obj))
|
(copy-segment segment obj))
|
||||||
|
|
||||||
(defmethod deserialize-from ::raw
|
(defmethod deserialize-from ::raw
|
||||||
|
|
@ -1155,9 +1206,9 @@
|
||||||
::pointer)
|
::pointer)
|
||||||
|
|
||||||
(defmethod serialize* ::c-string
|
(defmethod serialize* ::c-string
|
||||||
[obj _type scope]
|
[obj _type session]
|
||||||
(if obj
|
(if obj
|
||||||
(address-of (.allocateUtf8String (scope-allocator scope) ^String obj))
|
(address-of (.allocateUtf8String (session-allocator session) ^String obj))
|
||||||
(MemoryAddress/NULL)))
|
(MemoryAddress/NULL)))
|
||||||
|
|
||||||
(defmethod deserialize* ::c-string
|
(defmethod deserialize* ::c-string
|
||||||
|
|
@ -1174,7 +1225,7 @@
|
||||||
(into-array MemoryLayout items))))
|
(into-array MemoryLayout items))))
|
||||||
|
|
||||||
(defmethod serialize-into ::union
|
(defmethod serialize-into ::union
|
||||||
[obj [_union _types & {:keys [dispatch extract]} :as type] segment scope]
|
[obj [_union _types & {:keys [dispatch extract]} :as type] segment session]
|
||||||
(when-not dispatch
|
(when-not dispatch
|
||||||
(throw (ex-info "Attempted to serialize a union with no dispatch function"
|
(throw (ex-info "Attempted to serialize a union with no dispatch function"
|
||||||
{:type type
|
{:type type
|
||||||
|
|
@ -1186,7 +1237,7 @@
|
||||||
obj)
|
obj)
|
||||||
type
|
type
|
||||||
segment
|
segment
|
||||||
scope)))
|
session)))
|
||||||
|
|
||||||
(defmethod deserialize-from ::union
|
(defmethod deserialize-from ::union
|
||||||
[segment type]
|
[segment type]
|
||||||
|
|
@ -1203,7 +1254,7 @@
|
||||||
(into-array MemoryLayout fields))))
|
(into-array MemoryLayout fields))))
|
||||||
|
|
||||||
(defmethod serialize-into ::struct
|
(defmethod serialize-into ::struct
|
||||||
[obj [_struct fields] segment scope]
|
[obj [_struct fields] segment session]
|
||||||
(loop [offset 0
|
(loop [offset 0
|
||||||
fields fields]
|
fields fields]
|
||||||
(when (seq fields)
|
(when (seq fields)
|
||||||
|
|
@ -1211,7 +1262,7 @@
|
||||||
size (size-of type)]
|
size (size-of type)]
|
||||||
(serialize-into
|
(serialize-into
|
||||||
(get obj field) type
|
(get obj field) type
|
||||||
(slice segment offset size) scope)
|
(slice segment offset size) session)
|
||||||
(recur (long (+ offset size)) (rest fields))))))
|
(recur (long (+ offset size)) (rest fields))))))
|
||||||
|
|
||||||
(defmethod deserialize-from ::struct
|
(defmethod deserialize-from ::struct
|
||||||
|
|
@ -1237,7 +1288,7 @@
|
||||||
(MemoryLayout/paddingLayout (* 8 size)))
|
(MemoryLayout/paddingLayout (* 8 size)))
|
||||||
|
|
||||||
(defmethod serialize-into ::padding
|
(defmethod serialize-into ::padding
|
||||||
[_obj [_padding _size] _segment _scope]
|
[_obj [_padding _size] _segment _session]
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
(defmethod deserialize-from ::padding
|
(defmethod deserialize-from ::padding
|
||||||
|
|
@ -1253,9 +1304,9 @@
|
||||||
(c-layout type)))
|
(c-layout type)))
|
||||||
|
|
||||||
(defmethod serialize-into ::array
|
(defmethod serialize-into ::array
|
||||||
[obj [_array type count] segment scope]
|
[obj [_array type count] segment session]
|
||||||
(dorun
|
(dorun
|
||||||
(map #(serialize-into %1 type %2 scope)
|
(map #(serialize-into %1 type %2 session)
|
||||||
obj
|
obj
|
||||||
(slice-segments (slice segment 0 (* count (size-of type)))
|
(slice-segments (slice segment 0 (* count (size-of type)))
|
||||||
(size-of type)))))
|
(size-of type)))))
|
||||||
|
|
@ -1300,10 +1351,10 @@
|
||||||
variants))))
|
variants))))
|
||||||
|
|
||||||
(defmethod serialize* ::enum
|
(defmethod serialize* ::enum
|
||||||
[obj [_enum variants & {:keys [repr]}] scope]
|
[obj [_enum variants & {:keys [repr]}] session]
|
||||||
(serialize* ((enum-variants-map variants) obj)
|
(serialize* ((enum-variants-map variants) obj)
|
||||||
(or repr ::int)
|
(or repr ::int)
|
||||||
scope))
|
session))
|
||||||
|
|
||||||
(defmethod deserialize* ::enum
|
(defmethod deserialize* ::enum
|
||||||
[obj [_enum variants & {:keys [_repr]}]]
|
[obj [_enum variants & {:keys [_repr]}]]
|
||||||
|
|
@ -1318,9 +1369,9 @@
|
||||||
::int))
|
::int))
|
||||||
|
|
||||||
(defmethod serialize* ::flagset
|
(defmethod serialize* ::flagset
|
||||||
[obj [_flagset bits & {:keys [repr]}] scope]
|
[obj [_flagset bits & {:keys [repr]}] session]
|
||||||
(let [bits-map (enum-variants-map bits)]
|
(let [bits-map (enum-variants-map bits)]
|
||||||
(reduce #(bit-set %1 (get bits-map %2)) (serialize* 0 (or repr ::int) scope) obj)))
|
(reduce #(bit-set %1 (get bits-map %2)) (serialize* 0 (or repr ::int) session) obj)))
|
||||||
|
|
||||||
(defmethod deserialize* ::flagset
|
(defmethod deserialize* ::flagset
|
||||||
[obj [_flagset bits & {:keys [repr]}]]
|
[obj [_flagset bits & {:keys [repr]}]]
|
||||||
|
|
@ -1352,8 +1403,8 @@
|
||||||
[_type#]
|
[_type#]
|
||||||
(primitive-type aliased#))
|
(primitive-type aliased#))
|
||||||
(defmethod serialize* ~new-type
|
(defmethod serialize* ~new-type
|
||||||
[obj# _type# scope#]
|
[obj# _type# session#]
|
||||||
(serialize* obj# aliased# scope#))
|
(serialize* obj# aliased# session#))
|
||||||
(defmethod deserialize* ~new-type
|
(defmethod deserialize* ~new-type
|
||||||
[obj# _type#]
|
[obj# _type#]
|
||||||
(deserialize* obj# aliased#)))
|
(deserialize* obj# aliased#)))
|
||||||
|
|
@ -1362,8 +1413,8 @@
|
||||||
[_type#]
|
[_type#]
|
||||||
(c-layout aliased#))
|
(c-layout aliased#))
|
||||||
(defmethod serialize-into ~new-type
|
(defmethod serialize-into ~new-type
|
||||||
[obj# _type# segment# scope#]
|
[obj# _type# segment# session#]
|
||||||
(serialize-into obj# aliased# segment# scope#))
|
(serialize-into obj# aliased# segment# session#))
|
||||||
(defmethod deserialize-from ~new-type
|
(defmethod deserialize-from ~new-type
|
||||||
[segment# _type#]
|
[segment# _type#]
|
||||||
(deserialize-from segment# aliased#)))))
|
(deserialize-from segment# aliased#)))))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue