proxy [ThreadLocal] via thread-parameter; clojure.test/*testing-vars*
- (proxy [ThreadLocal] [] (initialValue [] body)) now builds a real per-thread store backed by a Chez thread-parameter, with a lazy initialValue; .get/.set/ .remove work. Other proxies stay nil. test.check's no-seed PRNG (next-rng) uses one, so gen/sample and gen/generate (and everything built on them) now work. - clojure.test/*testing-vars* (+ *report-counters*) are bound vars now, so a defspec run through its :test metadata / default reporter doesn't hit an unbound var. make test green (+1 corpus row), shakesmoke byte-identical. One re-mint (proxy).
This commit is contained in:
parent
f32bd335e3
commit
4d61145e9c
6 changed files with 587 additions and 558 deletions
|
|
@ -697,6 +697,22 @@
|
|||
(def-var! "clojure.core" "__register-class-methods!"
|
||||
(lambda (tag members) (register-tagged-methods! tag (jmap->static-alist members)) jolt-nil))
|
||||
|
||||
;; java.lang.ThreadLocal via a Chez thread-parameter: real per-thread storage with
|
||||
;; a lazy initialValue (the proxy macro lowers (proxy [ThreadLocal] …) to this).
|
||||
;; .get returns the thread's value, computing initialValue once; .set / .remove.
|
||||
(define tl-unset (list 'tl-unset))
|
||||
(define (jolt-make-thread-local init-thunk)
|
||||
(make-jhost "threadlocal" (vector (make-thread-parameter tl-unset) init-thunk)))
|
||||
(register-host-methods! "threadlocal"
|
||||
(list (cons "get" (lambda (self)
|
||||
(let* ((st (jhost-state self)) (tp (vector-ref st 0)) (v (tp)))
|
||||
(if (eq? v tl-unset)
|
||||
(let ((nv (jolt-invoke (vector-ref st 1)))) (tp nv) nv)
|
||||
v))))
|
||||
(cons "set" (lambda (self v) ((vector-ref (jhost-state self) 0) v) jolt-nil))
|
||||
(cons "remove" (lambda (self) ((vector-ref (jhost-state self) 0) tl-unset) jolt-nil))))
|
||||
(def-var! "jolt.host" "make-thread-local" jolt-make-thread-local)
|
||||
|
||||
;; Pluggable instance? — a library registers (fn [class-name-string val] -> true
|
||||
;; | false | nil); nil means "not my class, fall through". First non-nil wins.
|
||||
(define user-instance-checks '())
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -558,8 +558,14 @@
|
|||
(parse-extend-impls type-impls))))
|
||||
|
||||
;; extend is a real FUNCTION — defined above extend-type.
|
||||
;; JVM proxies are unsupported.
|
||||
(defmacro proxy [& args] nil)
|
||||
;; JVM proxies are unsupported in general, EXCEPT (proxy [ThreadLocal] [] (initialValue
|
||||
;; [] body)) — a per-thread store with a lazy initial value (test.check's no-seed
|
||||
;; PRNG uses one). Other proxies stay nil.
|
||||
(defmacro proxy [supers ctor-args & methods]
|
||||
(when (and (vector? supers) (= 1 (count supers))
|
||||
(let [s (name (first supers))] (or (= s "ThreadLocal") (= s "InheritableThreadLocal"))))
|
||||
(let [init (some (fn [m] (when (= "initialValue" (name (first m))) m)) methods)]
|
||||
`(jolt.host/make-thread-local (fn [] ~@(when init (nnext init)))))))
|
||||
;; definterface is JVM-only; bind the name to a marker and return the name (not a
|
||||
;; var), matching the JVM where definterface yields the interface Class.
|
||||
(defmacro definterface [name-sym & body]
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@
|
|||
(def once-fixtures (atom []))
|
||||
(def each-fixtures (atom []))
|
||||
|
||||
;; clojure.test/*testing-vars* — the stack of vars under test. Real clojure.test
|
||||
;; binds it around each test var; test.check's default reporter reads it, so a
|
||||
;; defspec run through its :test metadata doesn't blow up on an unbound var.
|
||||
(def ^:dynamic *testing-vars* (list))
|
||||
(def ^:dynamic *report-counters* nil)
|
||||
|
||||
(defn reset-report! []
|
||||
(reset! counters {:test 0 :pass 0 :fail 0 :error 0 :fails []})
|
||||
(reset! ctx-stack [])
|
||||
|
|
|
|||
|
|
@ -3385,4 +3385,5 @@
|
|||
{:suite "numbers / unchecked on doubles" :label "unchecked-multiply of doubles is a double, not a truncated long" :expected "3.0" :actual "(unchecked-multiply 1.5 2.0)"}
|
||||
{:suite "seq / take infinite count" :label "(take +Infinity coll) takes the whole coll" :expected "7" :actual "(count (take (/ 1.0 0.0) (range 7)))"}
|
||||
{:suite "host-interop / UUID + Long + shiftLeft" :label "(UUID. msb lsb), .shiftLeft, (Long. n)" :expected "[\"00000000-0000-007b-0000-0000000001c8\" 40 10 42]" :actual "[(str (java.util.UUID. 123 456)) (.shiftLeft 5 3) (.shiftRight 40 2) (Long. 42)]"}
|
||||
{:suite "host-interop / ThreadLocal proxy" :label "(proxy [ThreadLocal] [] (initialValue [] v)) get/set" :expected "[42 7]" :actual "(let [tl (proxy [ThreadLocal] [] (initialValue [] 42))] [(.get tl) (do (.set tl 7) (.get tl))])"}
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue