aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mux.go15
-rw-r--r--share.go52
-rw-r--r--srv.go52
3 files changed, 59 insertions, 60 deletions
diff --git a/mux.go b/mux.go
index 7de73a0..6e5dcdb 100644
--- a/mux.go
+++ b/mux.go
@@ -10,7 +10,7 @@ import (
// events and their draw functions get redirected to the root Env.
type Mux struct {
addEventsIn chan<- chan<- Event
- sizeSrv server[image.Rectangle]
+ size sharedVal[image.Rectangle]
draw chan<- func(draw.Image) image.Rectangle
}
@@ -20,11 +20,11 @@ type Mux struct {
// created by the Mux.
func NewMux(env Env) (mux *Mux, master Env) {
addEventsIn := make(chan chan<- Event)
- sizeSrv := newServer[image.Rectangle]()
+ size := newSharedVal[image.Rectangle]()
drawChan := make(chan func(draw.Image) image.Rectangle)
mux = &Mux{
addEventsIn: addEventsIn,
- sizeSrv: sizeSrv,
+ size: size,
draw: drawChan,
}
@@ -33,7 +33,7 @@ func NewMux(env Env) (mux *Mux, master Env) {
defer close(env.Draw())
defer close(addEventsIn)
- defer sizeSrv.close()
+ defer size.close()
defer func() {
for _, eventsIn := range eventsIns {
close(eventsIn)
@@ -52,7 +52,7 @@ func NewMux(env Env) (mux *Mux, master Env) {
return
}
if resize, ok := e.(Resize); ok {
- sizeSrv.update <- resize.Rectangle
+ size.set <- resize.Rectangle
}
for _, eventsIn := range eventsIns {
eventsIn <- e
@@ -88,9 +88,8 @@ func (mux *Mux) makeEnv(master bool) Env {
env := &muxEnv{eventsOut, drawChan}
mux.addEventsIn <- eventsIn
- // make sure to always send a resize event to a new Env if we got the size already
- // that means it missed the resize event by the root Env
- eventsIn <- Resize{mux.sizeSrv.get()}
+ // make sure to always send a resize event to a new Env
+ eventsIn <- Resize{mux.size.get()}
go func() {
func() {
diff --git a/share.go b/share.go
new file mode 100644
index 0000000..b370e5a
--- /dev/null
+++ b/share.go
@@ -0,0 +1,52 @@
+package gui
+
+// sharedVal is a concurrent interface to a piece of shared data.
+//
+// A client can read the data by sending a channel via request, and the stored value will
+// be sent back via the channel. The client is responsible for closing the channel.
+//
+// The stored value can be changed by sending the new value via set. Requests block until
+// the first value is received on set.
+//
+// A sharedVal should be closed after use.
+type sharedVal[T any] struct {
+ request chan<- chan T
+ set chan<- T
+}
+
+func newSharedVal[T any]() sharedVal[T] {
+ request := make(chan chan T)
+ set := make(chan T)
+ go func() {
+ val := <-set // wait for initial value
+ for {
+ select {
+ case v, ok := <-set:
+ if !ok { // closed
+ return
+ }
+ val = v
+ case req, ok := <-request:
+ if !ok { // closed
+ return
+ }
+ go func() { // don't wait for client to receive
+ req <- val
+ }()
+ }
+ }
+ }()
+ return sharedVal[T]{request, set}
+}
+
+// get makes a synchronous request and returns the stored value.
+func (sv sharedVal[T]) get() T {
+ c := make(chan T)
+ sv.request <- c
+ return <-c
+}
+
+func (sv sharedVal[T]) close() {
+ close(sv.request)
+ close(sv.set)
+}
diff --git a/srv.go b/srv.go
deleted file mode 100644
index 48cc3d3..0000000
--- a/srv.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package gui
-
-// server is a concurrent interface that stores a value and serves it to clients.
-// The stored value can be changed by sending the new value via update. server blocks
-// until the first value is received.
-//
-// A client can read the stored value by sending a channel via request. The server
-// responds by sending the value back via the channel. The client is responsible for
-// closing the channel.
-//
-// A server should be closed after use.
-type server[T any] struct {
- request chan<- chan T
- update chan<- T
-}
-
-func newServer[T any]() server[T] {
- request := make(chan chan T)
- update := make(chan T)
- go func() {
- val := <-update // wait for initial value
- for {
- select {
- case v, ok := <-update:
- if !ok { // closed
- return
- }
- val = v
- case req, ok := <-request:
- if !ok { // closed
- return
- }
- go func() { // don't wait for client to receive
- req <- val
- }()
- }
- }
- }()
- return server[T]{request, update}
-}
-
-// get makes a synchronous request to the server and returns the stored value.
-func (srv server[T]) get() T {
- c := make(chan T)
- srv.request <- c
- return <-c
-}
-
-func (srv server[T]) close() {
- close(srv.request)
- close(srv.update)
-}