Change defcfn to use a fn-tail to allow multiple arity wrappers

This commit is contained in:
Joshua Suskalo 2021-09-17 11:34:03 -05:00
parent fce3675a4b
commit ada787a72b

View file

@ -701,8 +701,9 @@
:native-arglist (s/coll-of qualified-keyword? :kind vector?) :native-arglist (s/coll-of qualified-keyword? :kind vector?)
:return-type qualified-keyword? :return-type qualified-keyword?
:fn-tail (s/? :fn-tail (s/?
(s/cat :arglist (s/coll-of simple-symbol? :kind vector?) (s/nonconforming
:body (s/* any?))))) (s/cat :arglist (s/coll-of simple-symbol? :kind vector?)
:body (s/* any?))))))
(defmacro defcfn (defmacro defcfn
"Defines a Clojure function which maps to a native function. "Defines a Clojure function which maps to a native function.
@ -711,23 +712,23 @@
`symbol` is a symbol or string naming the library symbol to link against. `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. `arg-types` is a vector of qualified keywords representing the argument types.
`ret-type` is a single qualified keyword representing the return type. `ret-type` is a single qualified keyword representing the return type.
`arglist` is a binding vector for the symbols used in the wrapping function. `fn-tail` is the body of the function (potentially with multiple arities)
`body` is a function body referring to `arglist`. During the execution of the which wraps the native one. Inside the function, `name` is bound to a function
body, `name` is bound to a function that will serialize its arguments, call that will serialize its arguments, call the native function, and deserialize
the native function, and deserialize its return type. If any body is present, its return type. If any body is present, you must call this function in order
you must call this function in order to call the native code. to call the native code.
If no `arglist` and `body` is provided, then the resulting function will If no `fn-tail` is provided, then the resulting function will simply serialize
simply serialize the arguments according to `arg-types`, call the native the arguments according to `arg-types`, call the native function, and
function, and deserialize the return value. deserialize the return value.
The number of args in `arglist` need not match the number of `arg-types` for The number of args in the `fn-tail` need not match the number of `arg-types`
the native function. It need only call the native wrapper function with the for the native function. It need only call the native wrapper function with
correct arguments. the correct arguments.
See [[serialize]], [[deserialize]], [[make-downcall]]." See [[serialize]], [[deserialize]], [[make-downcall]]."
{:arglists '([name docstring? attr-map? symbol arg-types ret-type] {:arglists '([name docstring? attr-map? symbol arg-types ret-type]
[name docstring? attr-map? symbol arg-types ret-type arglist & body])} [name docstring? attr-map? symbol arg-types ret-type & fn-tail])}
[& args] [& args]
(let [args (s/conform ::defcfn-args args) (let [args (s/conform ::defcfn-args args)
scope (gensym "scope") scope (gensym "scope")
@ -757,8 +758,7 @@
arg-syms arg-types)) arg-syms arg-types))
~ret-type)))) ~ret-type))))
fun# ~(if (:fn-tail args) fun# ~(if (:fn-tail args)
`(fn ~(-> args :fn-tail :arglist) `(fn ~@(:fn-tail args))
~@(-> args :fn-tail :body))
(:name args))] (:name args))]
(def (def
~(with-meta (:name args) ~(with-meta (:name args)