Skip to content

Commit

Permalink
Add cljd.dart.isolates and update the isolates sample
Browse files Browse the repository at this point in the history
  • Loading branch information
cgrand committed Nov 17, 2023
1 parent 28a6bcd commit c79e92c
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 28 deletions.
53 changes: 53 additions & 0 deletions clj/src/cljd/dart/isolates.cljd
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
(ns cljd.dart.isolates
(:require ["dart:isolate" :as dart:isolate]))

(defn- named-recvs [names]
(into {} (map (fn [k] [k (dart:isolate/ReceivePort)])) names))

(defn- sends-from-recvs [recvs-map]
(into recvs-map (map (fn [[k ^dart:isolate/ReceivePort recv]] [k (.-sendPort recv)])) recvs-map))

(defn- boot-isolate [[f handshake outs ins]]
(let [ins (named-recvs ins)]
(.send ^dart:isolate/SendPort handshake (sends-from-recvs ins))
(f (into outs ins))))

(defn spawn!
"Spawn a function f of one argument (a map whose values are ReceivePorts or SendPorts).
Returns a map with keys :isolate (a reference to the spawned Isolate), and :ports a map
(a map whose values are ReceivePorts or SendPorts).
Supported options are :ports, :paused, :debug-name, :errors-are-fatal, :on-exit and :on-error.
:ports is a map of identifiers to :recv or :send. :recv and :send are expressed from the point
of view of the caller: if you specify :send (resp. :recv) you get a SendPort (resp. ReceivePort)
under :ports in the return value and the new isolate gets the matching ReceivePort (resp. SendPort).
Thus these 3 maps (:ports as option, :ports in return value and the map passed to f) share the
same keyset.
If :ports is omitted, {:in :send :out :recv} is assumed to start an isolate with one input and one output.
See https://api.dart.dev/stable/dart-isolate/Isolate/spawn.html for the role of
:paused, :debug-name, :errors-are-fatal, :on-exit and :on-error.
The value under :in is a SendPort connected to the ReceivePort passed as in to f.
The value under :out is a ReceivePort connected to the SendPort passed as out to f."
([f] (spawn! f {}))
([f {:keys [ports paused debug-name errors-are-fatal on-exit on-error]
:or {ports {:in :send :out :recv}
errors-are-fatal true
paused false}}]
(let [handshake (dart:isolate/ReceivePort)
outs (named-recvs (keep (fn [[k v]] (case v :recv k :send nil)) ports))
isolate
(await
(dart:isolate/Isolate.spawn
boot-isolate
[f (.-sendPort handshake) (sends-from-recvs outs) (keep (fn [[k v]] (case v :recv nil :send k)) ports)]
.errorsAreFatal errors-are-fatal
.paused paused
.debugName debug-name
.onExit on-exit
.onError on-error))
ins (await (.-first handshake))]
{:isolate isolate
:ports (into ins outs)})))
35 changes: 7 additions & 28 deletions samples/isolates/src/sample/isolates.cljd
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,8 @@
"Isolate example, original code by Ian Fernandez (https://github.com/ianffcs)"
(:require ["package:flutter/material.dart" :as m]
["dart:isolate" :as dart:isolate]
[cljd.flutter :as f]))

(defn- boot-isolate [[f handshake out]]
(let [in (dart:isolate/ReceivePort)]
(.send ^dart:isolate/SendPort handshake (.-sendPort in))
(f in out)))

(defn spawn!
"Spawn a function f of two arguments (in and out).
Returns a map with keys :in, :isolate and :out.
The value under :in is a SendPort connected to the ReceivePort passed as in to f.
The value under :out is a ReceivePort connected to the SendPort passed as out to f."
[f]
(let [handshake (dart:isolate/ReceivePort)
out (dart:isolate/ReceivePort)
isolate
(await
(dart:isolate/Isolate.spawn
boot-isolate
[f (.-sendPort handshake) (.-sendPort out)]))]
{:isolate isolate
:in (await (.-first handshake))
:out out}))
[cljd.flutter :as f]
[cljd.dart.isolates :as di]))

(def isolate-ui
(f/widget
Expand All @@ -45,12 +24,12 @@
.onPressed (case status
(nil :done)
(fn []
(let [{:keys [out] :as m}
(let [{{:keys [out]} :ports}
(await
(spawn! (fn [in out]
(dotimes [_ (* 1000 1000 1000 10)])
(.send ^dart:isolate/SendPort out :done)
(dart:core/print "done"))))]
(di/spawn! (fn [{:keys [in out]}]
(dotimes [_ (* 1000 1000 1000 10)])
(.send ^dart:isolate/SendPort out :done)
(dart:core/print "done"))))]
(reset! running out)
nil))
; nil disables the button
Expand Down

0 comments on commit c79e92c

Please sign in to comment.