mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 14:00:37 +00:00
🚧 WIP Step 16.1 Relax scene macro constraints
This commit is contained in:
parent
6cec9d7be4
commit
aa7bd111f8
@ -21,21 +21,48 @@
|
||||
`(benches.render-wasm.scenes.core/register-scene!
|
||||
(assoc ~opts :id ~id :ns ~(str *ns*) :build ~build)))
|
||||
|
||||
(defn- one-argument-fn-form?
|
||||
"True for functions of arity 1"
|
||||
[form]
|
||||
(when (and (seq? form)
|
||||
(contains? '#{fn fn* clojure.core/fn cljs.core/fn} (first form)))
|
||||
(let [clauses (if (symbol? (second form)) (nnext form) (next form))
|
||||
params (cond
|
||||
(vector? (first clauses))
|
||||
(first clauses)
|
||||
(and (= 1 (count clauses))
|
||||
(seq? (first clauses)))
|
||||
(ffirst clauses))]
|
||||
(and (vector? params)
|
||||
(= 1 (count params))
|
||||
(not= '& (first params))))))
|
||||
|
||||
(defn- case-registration-form
|
||||
[id scene opts run-fn]
|
||||
(let [options (gensym "options")]
|
||||
`(let [~options ~opts]
|
||||
(when (contains? ~options :run!)
|
||||
(throw (ex-info (str "defcase " ~id " requires its run function as the fourth argument")
|
||||
{:type :benches.render-wasm.scenes.core/invalid-run-function
|
||||
:id ~id})))
|
||||
(benches.render-wasm.scenes.core/register-case!
|
||||
(assoc ~options :id ~id :scene ~scene :ns ~(str *ns*)
|
||||
~@(when run-fn [:run! run-fn]))))))
|
||||
|
||||
(defmacro defcase
|
||||
"Registers a case for `scene` and returns its id.
|
||||
|
||||
The optional body threads the injected runtime as `rtx` and becomes the
|
||||
case's browser-side run function. The quoted body source travels with the
|
||||
registration for validation; case collection strips the body and the
|
||||
source before handing descriptors to the runner."
|
||||
[id scene opts & body]
|
||||
(if (seq body)
|
||||
`(benches.render-wasm.scenes.core/register-case!
|
||||
(assoc ~opts
|
||||
:id ~id
|
||||
:scene ~scene
|
||||
:ns ~(str *ns*)
|
||||
:run! (fn [~'rtx] ~@body)
|
||||
:body-source '~body))
|
||||
`(benches.render-wasm.scenes.core/register-case!
|
||||
(assoc ~opts :id ~id :scene ~scene :ns ~(str *ns*)))))
|
||||
An optional inline, one-argument function becomes `:run!`; its argument
|
||||
name is chosen by the caller. Other function forms fail at expansion.
|
||||
Ticket 14 will call it. Case collection omits it from descriptors. Example:
|
||||
|
||||
(defcase :rects/pan :rects options (fn [context] (pan! context)))"
|
||||
([id scene opts]
|
||||
(case-registration-form id scene opts nil))
|
||||
([id scene opts run-fn]
|
||||
(when-not (one-argument-fn-form? run-fn)
|
||||
(throw (ex-info (str "defcase " id " requires an inline one-argument function")
|
||||
{:type ::invalid-run-function
|
||||
:id id
|
||||
:form run-fn})))
|
||||
(case-registration-form id scene opts run-fn)))
|
||||
|
||||
@ -7,9 +7,9 @@
|
||||
(ns benches.render-wasm.scenes.core
|
||||
"Registry and contract for renderer benchmark scenes and cases.
|
||||
|
||||
Scene namespaces register themselves at load time through the `defscene`
|
||||
and `defcase` macros in `core.clj`. We don't import browser or renderer
|
||||
code here.
|
||||
Scene namespaces register themselves through the `defscene` and
|
||||
`defcase` macros in `core.clj`. This namespace imports no browser or
|
||||
renderer code.
|
||||
|
||||
- A scene declares an id, a version, a human description, a closed
|
||||
parameters schema and a one-argument build function.
|
||||
@ -18,7 +18,7 @@
|
||||
identity and run function.
|
||||
|
||||
Collection validates every declaration, derives each scene seed and
|
||||
returns plain data"
|
||||
returns plain data."
|
||||
(:require
|
||||
[app.common.schema :as sm]
|
||||
[app.common.transit :as t]
|
||||
@ -28,8 +28,8 @@
|
||||
;; Runtime contract
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; rtx is the case execution context. The driver builds one map per attempt,
|
||||
;; calls the case body with it, and reads it back at completion:
|
||||
;; Ticket 14 will define rtx as the case execution context. Its proposed
|
||||
;; fields are:
|
||||
;;
|
||||
;; :case the collected case descriptor (id, scene, params, view,
|
||||
;; context, completion, batch-size, operation)
|
||||
@ -42,18 +42,15 @@
|
||||
;; :sleep (fn [ms] ...) promise
|
||||
;; :check zero-arg guard covering cancellation, deadline, context loss
|
||||
;;
|
||||
;; Ops take rtx first and return it, or a promise of it. Case bodies thread
|
||||
;; rtx with `->`; the body's value is the rtx the driver collects. The
|
||||
;; driver, the clock/scheduling helpers and the op vocabulary arrive with
|
||||
;; tickets 05/06/14; this namespace fixes the binding name, the single
|
||||
;; threaded value, and the body shape checked below.
|
||||
;; Case run functions take one runtime argument. The current bridge uses case
|
||||
;; metadata and does not run these functions.
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Node/browser dependency contract (runtime wiring pending in ticket 06)
|
||||
;; Node/browser dependency contract (case execution pending in ticket 14)
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Scene declarations and bodies load in both Node and browser. Only the
|
||||
;; browser driver executes bodies. Their transitive imports must stay safe
|
||||
;; Scene declarations and bodies load in both Node and browser. Ticket 14's
|
||||
;; browser driver will execute bodies. Their transitive imports must stay safe
|
||||
;; for Node; removing :run! from descriptors does not isolate dependencies.
|
||||
;;
|
||||
;; If an operation needs a browser API/helper, keep that import in a browser
|
||||
@ -121,8 +118,7 @@
|
||||
[:batch-size {:optional true} [:int {:min 1}]]
|
||||
[:operation {:optional true} [:map]]
|
||||
[:preparation {:optional true} [:map]]
|
||||
[:run! {:optional true} fn?]
|
||||
[:body-source {:optional true} [:fn seq?]]])
|
||||
[:run! {:optional true} fn?]])
|
||||
|
||||
(def schema:collected-case
|
||||
[:map {:closed true}
|
||||
@ -170,47 +166,10 @@
|
||||
(update :scene-order conj id))))))
|
||||
id)
|
||||
|
||||
(defn- thread-form?
|
||||
[form]
|
||||
(and (seq? form)
|
||||
(contains? '#{-> clojure.core/->} (first form))
|
||||
(= 'rtx (second form))))
|
||||
|
||||
(defn- valid-tail?
|
||||
[form]
|
||||
(cond
|
||||
(thread-form? form)
|
||||
true
|
||||
|
||||
(and (seq? form) (contains? '#{do let} (first form)))
|
||||
(valid-tail? (last form))
|
||||
|
||||
:else
|
||||
false))
|
||||
|
||||
(defn check-body-source!
|
||||
"Validates a defcase body source and returns it unchanged. Every value
|
||||
the body can return threads the injected runtime: a `(-> rtx ...)`
|
||||
pipeline, optionally preceded by setup forms or wrapped in `let`/`do`.
|
||||
Anything else throws ::invalid-case. The checker covers shape only;
|
||||
review and fake-runtime unit tests cover sense."
|
||||
[id body-source]
|
||||
(when-not (and (seq body-source) (valid-tail? (last body-source)))
|
||||
(throw (ex-info (str "defcase " id " threads the injected runtime: "
|
||||
"its value is a (-> rtx ...) pipeline, "
|
||||
"optionally wrapped in let/do. Got: "
|
||||
(pr-str body-source))
|
||||
{:type ::invalid-case
|
||||
:id id})))
|
||||
body-source)
|
||||
|
||||
(defn register-case!
|
||||
"Adds `bench-case` to the registry with the same replace/reject semantics
|
||||
as register-scene!. A declared body source is validated here, at load
|
||||
time, so a malformed pipeline fails before any browser work."
|
||||
[{:keys [id ns body-source] :as bench-case}]
|
||||
(when (some? body-source)
|
||||
(check-body-source! id body-source))
|
||||
as register-scene!."
|
||||
[{:keys [id ns] :as bench-case}]
|
||||
(let [existing (get-in @registry [:cases id])]
|
||||
(when (and (some? existing) (not= ns (:ns existing)))
|
||||
(throw (ex-info (str "duplicate case id: " id)
|
||||
@ -263,10 +222,7 @@
|
||||
(get-in @registry [:scenes id]))
|
||||
|
||||
(defn registered-case
|
||||
"Full registered entry for a case id, including the browser-side run
|
||||
function when the case declares one. The browser bridge resolves
|
||||
executions through this namespace; the Node runner only reads collected
|
||||
descriptors."
|
||||
"Full case entry, including `:run!` when the case declares one."
|
||||
[id]
|
||||
(get-in @registry [:cases id]))
|
||||
|
||||
@ -399,8 +355,8 @@
|
||||
(catch :default _ false)))
|
||||
|
||||
(defn project-case
|
||||
"Plain-data projection of a registered case: internal keys (`:ns`, `:run!`,
|
||||
`:body-source`) stripped, collection defaults applied."
|
||||
"Plain-data projection of a registered case: internal keys (`:ns`, `:run!`)
|
||||
stripped, collection defaults applied."
|
||||
[bench-case]
|
||||
(-> bench-case
|
||||
(select-keys [:id :scene :params :view :context :completion :batch-size
|
||||
@ -409,7 +365,7 @@
|
||||
(update :batch-size #(or % 1))
|
||||
(update :preparation #(or % {:version 1}))))
|
||||
|
||||
(defn check-collected-case!
|
||||
(defn check-collected-case
|
||||
"Validates a collected case descriptor and returns it unchanged.
|
||||
|
||||
Rejects anything that fails the schema and anything that does not survive
|
||||
|
||||
@ -12,19 +12,8 @@
|
||||
`build` produces the scene snapshot; `defscene` and `defcase` declare
|
||||
the scene and its standard cases. The three cases share parameters, so
|
||||
they render the same scene. The path and effect scenes arrive in
|
||||
tickets07/08.
|
||||
|
||||
Operation bodies are deferred to tickets05/06. The intended threaded
|
||||
shape is:
|
||||
|
||||
(defcase :rects/pan :rects {...}
|
||||
(-> rtx
|
||||
(restore! base-view)
|
||||
(pan! {:frames 20 :distance [120 60] :settle-ms 100})
|
||||
(drain! :full)))
|
||||
|
||||
where `rtx` is the injected runtime and each operation contributes its
|
||||
plain-data identity to the collected case."
|
||||
tickets 07/08. The bridge supplies the current pan and zoom gestures;
|
||||
scene case bodies arrive with ticket 14."
|
||||
(:require
|
||||
[app.common.schema :as sm]
|
||||
[benches.render-wasm.scenes.builder :as sb :include-macros true]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user