From c0d845612717b364aaa70ed6c943454d6f03f3e6 Mon Sep 17 00:00:00 2001 From: Jacalz Date: Wed, 8 Jan 2025 13:32:59 +0100 Subject: [PATCH 1/2] Make generic async.UnboundedChan work on Go 1.19 I found a (kind of ugly) way to work around lack for setting zero types using generics. This means that the generic channel can be used on Go 1.19 and thus can the old generator script be removed. --- data/binding/queue_test.go | 2 +- internal/app/lifecycle.go | 4 +- internal/async/{chan_func.go => chan.go} | 41 +++--- internal/async/chan_canvasobject.go | 102 -------------- internal/async/chan_go1.21.go | 128 ----------------- internal/async/chan_interface.go | 100 -------------- internal/async/chan_test.go | 12 +- internal/async/gen.go | 169 ----------------------- internal/driver/mobile/app/app.go | 4 +- internal/driver/mobile/driver.go | 4 +- 10 files changed, 32 insertions(+), 534 deletions(-) rename internal/async/{chan_func.go => chan.go} (66%) mode change 100755 => 100644 delete mode 100755 internal/async/chan_canvasobject.go delete mode 100644 internal/async/chan_go1.21.go delete mode 100755 internal/async/chan_interface.go delete mode 100644 internal/async/gen.go diff --git a/data/binding/queue_test.go b/data/binding/queue_test.go index 221c227aff..c1d2c7eb3d 100644 --- a/data/binding/queue_test.go +++ b/data/binding/queue_test.go @@ -44,7 +44,7 @@ func TestQueueItem(t *testing.T) { func TestMakeInfiniteQueue(t *testing.T) { var wg sync.WaitGroup - queue := async.NewUnboundedFuncChan() + queue := async.NewUnboundedChan[func()]() wg.Add(1) c := 0 diff --git a/internal/app/lifecycle.go b/internal/app/lifecycle.go index f41aeda099..ec9d7af171 100644 --- a/internal/app/lifecycle.go +++ b/internal/app/lifecycle.go @@ -20,7 +20,7 @@ type Lifecycle struct { onStoppedHookExecuted func() - eventQueue *async.UnboundedFuncChan + eventQueue *async.UnboundedChan[func()] } // SetOnStoppedHookExecuted is an internal function that lets Fyne schedule a clean-up after @@ -112,7 +112,7 @@ func (l *Lifecycle) DestroyEventQueue() { // InitEventQueue initializes the event queue. func (l *Lifecycle) InitEventQueue() { // This channel should be closed when the window is closed. - l.eventQueue = async.NewUnboundedFuncChan() + l.eventQueue = async.NewUnboundedChan[func()]() } // QueueEvent uses this method to queue up a callback that handles an event. This ensures diff --git a/internal/async/chan_func.go b/internal/async/chan.go old mode 100755 new mode 100644 similarity index 66% rename from internal/async/chan_func.go rename to internal/async/chan.go index 26e2e926f9..7afe18d8c8 --- a/internal/async/chan_func.go +++ b/internal/async/chan.go @@ -1,23 +1,20 @@ -//go:build !go1.21 - -// Code generated by go run gen.go; DO NOT EDIT. package async -// UnboundedFuncChan is a channel with an unbounded buffer for caching +// UnboundedChan is a channel with an unbounded buffer for caching // Func objects. A channel must be closed via Close method. -type UnboundedFuncChan struct { - in, out chan func() +type UnboundedChan[T any] struct { + in, out chan T close chan struct{} - q []func() + q []T } -// NewUnboundedFuncChan returns a unbounded channel with unlimited capacity. -func NewUnboundedFuncChan() *UnboundedFuncChan { - ch := &UnboundedFuncChan{ - // The size of Func is less than 16 bytes, we use 16 to fit +// NewUnboundedChan returns a unbounded channel with unlimited capacity. +func NewUnboundedChan[T any]() *UnboundedChan[T] { + ch := &UnboundedChan[T]{ + // The size of Func, Interface, and CanvasObject are all less than 16 bytes, we use 16 to fit // a CPU cache line (L2, 256 Bytes), which may reduce cache misses. - in: make(chan func(), 16), - out: make(chan func(), 16), + in: make(chan T, 16), + out: make(chan T, 16), close: make(chan struct{}), } go ch.processing() @@ -26,22 +23,22 @@ func NewUnboundedFuncChan() *UnboundedFuncChan { // In returns the send channel of the given channel, which can be used to // send values to the channel. -func (ch *UnboundedFuncChan) In() chan<- func() { return ch.in } +func (ch *UnboundedChan[T]) In() chan<- T { return ch.in } // Out returns the receive channel of the given channel, which can be used // to receive values from the channel. -func (ch *UnboundedFuncChan) Out() <-chan func() { return ch.out } +func (ch *UnboundedChan[T]) Out() <-chan T { return ch.out } // Close closes the channel. -func (ch *UnboundedFuncChan) Close() { ch.close <- struct{}{} } +func (ch *UnboundedChan[T]) Close() { ch.close <- struct{}{} } -func (ch *UnboundedFuncChan) processing() { +func (ch *UnboundedChan[T]) processing() { // This is a preallocation of the internal unbounded buffer. // The size is randomly picked. But if one changes the size, the // reallocation size at the subsequent for loop should also be // changed too. Furthermore, there is no memory leak since the // queue is garbage collected. - ch.q = make([]func(), 0, 1<<10) + ch.q = make([]T, 0, 1<<10) for { select { case e, ok := <-ch.in: @@ -59,7 +56,7 @@ func (ch *UnboundedFuncChan) processing() { for len(ch.q) > 0 { select { case ch.out <- ch.q[0]: - ch.q[0] = nil // de-reference earlier to help GC + ch.q[0] = *new(T) // de-reference earlier to help GC (use clear() when Go 1.21 is base) ch.q = ch.q[1:] case e, ok := <-ch.in: if !ok { @@ -77,12 +74,12 @@ func (ch *UnboundedFuncChan) processing() { // If the remaining capacity is too small, we prefer to // reallocate the entire buffer. if cap(ch.q) < 1<<5 { - ch.q = make([]func(), 0, 1<<10) + ch.q = make([]T, 0, 1<<10) } } } -func (ch *UnboundedFuncChan) closed() { +func (ch *UnboundedChan[T]) closed() { close(ch.in) for e := range ch.in { ch.q = append(ch.q, e) @@ -90,7 +87,7 @@ func (ch *UnboundedFuncChan) closed() { for len(ch.q) > 0 { select { case ch.out <- ch.q[0]: - ch.q[0] = nil // de-reference earlier to help GC + ch.q[0] = *new(T) // de-reference earlier to help GC (use clear() when Go 1.21 is base) ch.q = ch.q[1:] default: } diff --git a/internal/async/chan_canvasobject.go b/internal/async/chan_canvasobject.go deleted file mode 100755 index 6af88ba323..0000000000 --- a/internal/async/chan_canvasobject.go +++ /dev/null @@ -1,102 +0,0 @@ -//go:build !go1.21 - -// Code generated by go run gen.go; DO NOT EDIT. -package async - -import "fyne.io/fyne/v2" - -// UnboundedCanvasObjectChan is a channel with an unbounded buffer for caching -// CanvasObject objects. A channel must be closed via Close method. -type UnboundedCanvasObjectChan struct { - in, out chan fyne.CanvasObject - close chan struct{} - q []fyne.CanvasObject -} - -// NewUnboundedCanvasObjectChan returns a unbounded channel with unlimited capacity. -func NewUnboundedCanvasObjectChan() *UnboundedCanvasObjectChan { - ch := &UnboundedCanvasObjectChan{ - // The size of CanvasObject is less than 16 bytes, we use 16 to fit - // a CPU cache line (L2, 256 Bytes), which may reduce cache misses. - in: make(chan fyne.CanvasObject, 16), - out: make(chan fyne.CanvasObject, 16), - close: make(chan struct{}), - } - go ch.processing() - return ch -} - -// In returns the send channel of the given channel, which can be used to -// send values to the channel. -func (ch *UnboundedCanvasObjectChan) In() chan<- fyne.CanvasObject { return ch.in } - -// Out returns the receive channel of the given channel, which can be used -// to receive values from the channel. -func (ch *UnboundedCanvasObjectChan) Out() <-chan fyne.CanvasObject { return ch.out } - -// Close closes the channel. -func (ch *UnboundedCanvasObjectChan) Close() { ch.close <- struct{}{} } - -func (ch *UnboundedCanvasObjectChan) processing() { - // This is a preallocation of the internal unbounded buffer. - // The size is randomly picked. But if one changes the size, the - // reallocation size at the subsequent for loop should also be - // changed too. Furthermore, there is no memory leak since the - // queue is garbage collected. - ch.q = make([]fyne.CanvasObject, 0, 1<<10) - for { - select { - case e, ok := <-ch.in: - if !ok { - // We don't want the input channel be accidentally closed - // via close() instead of Close(). If that happens, it is - // a misuse, do a panic as warning. - panic("async: misuse of unbounded channel, In() was closed") - } - ch.q = append(ch.q, e) - case <-ch.close: - ch.closed() - return - } - for len(ch.q) > 0 { - select { - case ch.out <- ch.q[0]: - ch.q[0] = nil // de-reference earlier to help GC - ch.q = ch.q[1:] - case e, ok := <-ch.in: - if !ok { - // We don't want the input channel be accidentally closed - // via close() instead of Close(). If that happens, it is - // a misuse, do a panic as warning. - panic("async: misuse of unbounded channel, In() was closed") - } - ch.q = append(ch.q, e) - case <-ch.close: - ch.closed() - return - } - } - // If the remaining capacity is too small, we prefer to - // reallocate the entire buffer. - if cap(ch.q) < 1<<5 { - ch.q = make([]fyne.CanvasObject, 0, 1<<10) - } - } -} - -func (ch *UnboundedCanvasObjectChan) closed() { - close(ch.in) - for e := range ch.in { - ch.q = append(ch.q, e) - } - for len(ch.q) > 0 { - select { - case ch.out <- ch.q[0]: - ch.q[0] = nil // de-reference earlier to help GC - ch.q = ch.q[1:] - default: - } - } - close(ch.out) - close(ch.close) -} diff --git a/internal/async/chan_go1.21.go b/internal/async/chan_go1.21.go deleted file mode 100644 index 5e912b124d..0000000000 --- a/internal/async/chan_go1.21.go +++ /dev/null @@ -1,128 +0,0 @@ -//go:build go1.21 - -package async - -import "fyne.io/fyne/v2" - -// UnboundedFuncChan is a channel with an unbounded buffer for caching -// Func objects. A channel must be closed via Close method -type UnboundedFuncChan = UnboundedChan[func()] - -// NewUnboundedFuncChan returns a unbounded channel, of func(), with unlimited capacity. -func NewUnboundedFuncChan() *UnboundedFuncChan { - return NewUnboundedChan[func()]() -} - -// UnboundedInterfaceChan is a channel with an unbounded buffer for caching -// Interface objects. A channel must be closed via Close method. -type UnboundedInterfaceChan = UnboundedChan[any] - -// NewUnboundedInterfaceChan returns a unbounded channel, of any type, with unlimited capacity. -func NewUnboundedInterfaceChan() *UnboundedInterfaceChan { - return NewUnboundedChan[any]() -} - -// UnboundedCanvasObjectChan is a channel with an unbounded buffer for caching -// CanvasObject objects. A channel must be closed via Close method. -type UnboundedCanvasObjectChan = UnboundedChan[fyne.CanvasObject] - -// NewUnboundedCanvasObjectChan returns a unbounded channel, of canvas objects, with unlimited capacity. -func NewUnboundedCanvasObjectChan() *UnboundedChan[fyne.CanvasObject] { - return NewUnboundedChan[fyne.CanvasObject]() -} - -// UnboundedChan is a channel with an unbounded buffer for caching -// Func objects. A channel must be closed via Close method. -type UnboundedChan[T any] struct { - in, out chan T - close chan struct{} - q []T -} - -// NewUnboundedChan returns a unbounded channel with unlimited capacity. -func NewUnboundedChan[T any]() *UnboundedChan[T] { - ch := &UnboundedChan[T]{ - // The size of Func, Interface, and CanvasObject are all less than 16 bytes, we use 16 to fit - // a CPU cache line (L2, 256 Bytes), which may reduce cache misses. - in: make(chan T, 16), - out: make(chan T, 16), - close: make(chan struct{}), - } - go ch.processing() - return ch -} - -// In returns the send channel of the given channel, which can be used to -// send values to the channel. -func (ch *UnboundedChan[T]) In() chan<- T { return ch.in } - -// Out returns the receive channel of the given channel, which can be used -// to receive values from the channel. -func (ch *UnboundedChan[T]) Out() <-chan T { return ch.out } - -// Close closes the channel. -func (ch *UnboundedChan[T]) Close() { ch.close <- struct{}{} } - -func (ch *UnboundedChan[T]) processing() { - // This is a preallocation of the internal unbounded buffer. - // The size is randomly picked. But if one changes the size, the - // reallocation size at the subsequent for loop should also be - // changed too. Furthermore, there is no memory leak since the - // queue is garbage collected. - ch.q = make([]T, 0, 1<<10) - for { - select { - case e, ok := <-ch.in: - if !ok { - // We don't want the input channel be accidentally closed - // via close() instead of Close(). If that happens, it is - // a misuse, do a panic as warning. - panic("async: misuse of unbounded channel, In() was closed") - } - ch.q = append(ch.q, e) - case <-ch.close: - ch.closed() - return - } - for len(ch.q) > 0 { - select { - case ch.out <- ch.q[0]: - clear(ch.q[:1]) // de-reference earlier to help GC - ch.q = ch.q[1:] - case e, ok := <-ch.in: - if !ok { - // We don't want the input channel be accidentally closed - // via close() instead of Close(). If that happens, it is - // a misuse, do a panic as warning. - panic("async: misuse of unbounded channel, In() was closed") - } - ch.q = append(ch.q, e) - case <-ch.close: - ch.closed() - return - } - } - // If the remaining capacity is too small, we prefer to - // reallocate the entire buffer. - if cap(ch.q) < 1<<5 { - ch.q = make([]T, 0, 1<<10) - } - } -} - -func (ch *UnboundedChan[T]) closed() { - close(ch.in) - for e := range ch.in { - ch.q = append(ch.q, e) - } - for len(ch.q) > 0 { - select { - case ch.out <- ch.q[0]: - clear(ch.q[:1]) // de-reference earlier to help GC - ch.q = ch.q[1:] - default: - } - } - close(ch.out) - close(ch.close) -} diff --git a/internal/async/chan_interface.go b/internal/async/chan_interface.go deleted file mode 100755 index 85af28b10c..0000000000 --- a/internal/async/chan_interface.go +++ /dev/null @@ -1,100 +0,0 @@ -//go:build !go1.21 - -// Code generated by go run gen.go; DO NOT EDIT. -package async - -// UnboundedInterfaceChan is a channel with an unbounded buffer for caching -// Interface objects. A channel must be closed via Close method. -type UnboundedInterfaceChan struct { - in, out chan any - close chan struct{} - q []any -} - -// NewUnboundedInterfaceChan returns a unbounded channel with unlimited capacity. -func NewUnboundedInterfaceChan() *UnboundedInterfaceChan { - ch := &UnboundedInterfaceChan{ - // The size of Interface is less than 16 bytes, we use 16 to fit - // a CPU cache line (L2, 256 Bytes), which may reduce cache misses. - in: make(chan any, 16), - out: make(chan any, 16), - close: make(chan struct{}), - } - go ch.processing() - return ch -} - -// In returns the send channel of the given channel, which can be used to -// send values to the channel. -func (ch *UnboundedInterfaceChan) In() chan<- any { return ch.in } - -// Out returns the receive channel of the given channel, which can be used -// to receive values from the channel. -func (ch *UnboundedInterfaceChan) Out() <-chan any { return ch.out } - -// Close closes the channel. -func (ch *UnboundedInterfaceChan) Close() { ch.close <- struct{}{} } - -func (ch *UnboundedInterfaceChan) processing() { - // This is a preallocation of the internal unbounded buffer. - // The size is randomly picked. But if one changes the size, the - // reallocation size at the subsequent for loop should also be - // changed too. Furthermore, there is no memory leak since the - // queue is garbage collected. - ch.q = make([]any, 0, 1<<10) - for { - select { - case e, ok := <-ch.in: - if !ok { - // We don't want the input channel be accidentally closed - // via close() instead of Close(). If that happens, it is - // a misuse, do a panic as warning. - panic("async: misuse of unbounded channel, In() was closed") - } - ch.q = append(ch.q, e) - case <-ch.close: - ch.closed() - return - } - for len(ch.q) > 0 { - select { - case ch.out <- ch.q[0]: - ch.q[0] = nil // de-reference earlier to help GC - ch.q = ch.q[1:] - case e, ok := <-ch.in: - if !ok { - // We don't want the input channel be accidentally closed - // via close() instead of Close(). If that happens, it is - // a misuse, do a panic as warning. - panic("async: misuse of unbounded channel, In() was closed") - } - ch.q = append(ch.q, e) - case <-ch.close: - ch.closed() - return - } - } - // If the remaining capacity is too small, we prefer to - // reallocate the entire buffer. - if cap(ch.q) < 1<<5 { - ch.q = make([]any, 0, 1<<10) - } - } -} - -func (ch *UnboundedInterfaceChan) closed() { - close(ch.in) - for e := range ch.in { - ch.q = append(ch.q, e) - } - for len(ch.q) > 0 { - select { - case ch.out <- ch.q[0]: - ch.q[0] = nil // de-reference earlier to help GC - ch.q = ch.q[1:] - default: - } - } - close(ch.out) - close(ch.close) -} diff --git a/internal/async/chan_test.go b/internal/async/chan_test.go index 3b9dfbb2e8..7c017d53e7 100644 --- a/internal/async/chan_test.go +++ b/internal/async/chan_test.go @@ -19,7 +19,7 @@ func TestUnboundedChann(t *testing.T) { t.Run("any", func(t *testing.T) { t.Run("send", func(t *testing.T) { // Ensure send to an unbounded channel does not block. - c := async.NewUnboundedInterfaceChan() + c := async.NewUnboundedChan[any]() blocked := false wg.Add(1) go func() { @@ -40,7 +40,7 @@ func TestUnboundedChann(t *testing.T) { t.Run("recv", func(t *testing.T) { // Ensure that receive op from unbounded chan can happen on // the same goroutine of send op. - c := async.NewUnboundedInterfaceChan() + c := async.NewUnboundedChan[any]() wg.Add(1) go func() { defer wg.Done() @@ -53,7 +53,7 @@ func TestUnboundedChann(t *testing.T) { t.Run("order", func(t *testing.T) { // Ensure that the unbounded channel processes everything FIFO. - c := async.NewUnboundedInterfaceChan() + c := async.NewUnboundedChan[any]() for i := 0; i < 1<<11; i++ { c.In() <- i } @@ -70,7 +70,7 @@ func TestUnboundedChann(t *testing.T) { N := 10 n := 0 done := make(chan struct{}) - ch := async.NewUnboundedInterfaceChan() + ch := async.NewUnboundedChan[any]() for i := 0; i < N; i++ { ch.In() <- true } @@ -177,7 +177,7 @@ func TestUnboundedChann(t *testing.T) { func BenchmarkUnboundedChann(b *testing.B) { b.Run("any", func(b *testing.B) { b.Run("sync", func(b *testing.B) { - c := async.NewUnboundedInterfaceChan() + c := async.NewUnboundedChan[any]() b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { @@ -186,7 +186,7 @@ func BenchmarkUnboundedChann(b *testing.B) { } }) b.Run("async", func(b *testing.B) { - c := async.NewUnboundedInterfaceChan() + c := async.NewUnboundedChan[any]() b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { diff --git a/internal/async/gen.go b/internal/async/gen.go deleted file mode 100644 index 48d2701e4f..0000000000 --- a/internal/async/gen.go +++ /dev/null @@ -1,169 +0,0 @@ -//go:build ignore - -package main - -// To support a new type in this package, one can add types to `codes`, -// then run: `go generate ./...` in this folder, to generate more desired -// concrete typed unbounded channels or queues. -// -// Note that chan_struct.go is a specialized implementation for struct{} -// objects. If one changes the code template, then those changes should -// also be synced to chan_struct.go file manually. - -import ( - "bytes" - "fmt" - "go/format" - "io/fs" - "os" - "text/template" -) - -type data struct { - Type string - Name string - Imports string -} - -func main() { - codes := map[*template.Template]map[string]data{ - chanImpl: { - "chan_canvasobject.go": { - Type: "fyne.CanvasObject", - Name: "CanvasObject", - Imports: `import "fyne.io/fyne/v2"`, - }, - "chan_func.go": { - Type: "func()", - Name: "Func", - Imports: "", - }, - "chan_interface.go": { - Type: "any", - Name: "Interface", - Imports: "", - }, - }, - } - - for tmpl, types := range codes { - for fname, data := range types { - buf := &bytes.Buffer{} - err := tmpl.Execute(buf, data) - if err != nil { - panic(fmt.Errorf("failed to generate %s for type %s: %v", tmpl.Name(), data.Type, err)) - } - - code, err := format.Source(buf.Bytes()) - if err != nil { - panic(fmt.Errorf("failed to format the generated code:\n%v", err)) - } - - os.WriteFile(fname, code, fs.ModePerm) - } - } -} - -var chanImpl = template.Must(template.New("async").Parse(`//go:build !go1.21 - -// Code generated by go run gen.go; DO NOT EDIT. -package async - -{{.Imports}} - -// Unbounded{{.Name}}Chan is a channel with an unbounded buffer for caching -// {{.Name}} objects. A channel must be closed via Close method. -type Unbounded{{.Name}}Chan struct { - in, out chan {{.Type}} - close chan struct{} - q []{{.Type}} -} - -// NewUnbounded{{.Name}}Chan returns a unbounded channel with unlimited capacity. -func NewUnbounded{{.Name}}Chan() *Unbounded{{.Name}}Chan { - ch := &Unbounded{{.Name}}Chan{ - // The size of {{.Name}} is less than 16 bytes, we use 16 to fit - // a CPU cache line (L2, 256 Bytes), which may reduce cache misses. - in: make(chan {{.Type}}, 16), - out: make(chan {{.Type}}, 16), - close: make(chan struct{}), - } - go ch.processing() - return ch -} - -// In returns the send channel of the given channel, which can be used to -// send values to the channel. -func (ch *Unbounded{{.Name}}Chan) In() chan<- {{.Type}} { return ch.in } - -// Out returns the receive channel of the given channel, which can be used -// to receive values from the channel. -func (ch *Unbounded{{.Name}}Chan) Out() <-chan {{.Type}} { return ch.out } - -// Close closes the channel. -func (ch *Unbounded{{.Name}}Chan) Close() { ch.close <- struct{}{} } - -func (ch *Unbounded{{.Name}}Chan) processing() { - // This is a preallocation of the internal unbounded buffer. - // The size is randomly picked. But if one changes the size, the - // reallocation size at the subsequent for loop should also be - // changed too. Furthermore, there is no memory leak since the - // queue is garbage collected. - ch.q = make([]{{.Type}}, 0, 1<<10) - for { - select { - case e, ok := <-ch.in: - if !ok { - // We don't want the input channel be accidentally closed - // via close() instead of Close(). If that happens, it is - // a misuse, do a panic as warning. - panic("async: misuse of unbounded channel, In() was closed") - } - ch.q = append(ch.q, e) - case <-ch.close: - ch.closed() - return - } - for len(ch.q) > 0 { - select { - case ch.out <- ch.q[0]: - ch.q[0] = nil // de-reference earlier to help GC - ch.q = ch.q[1:] - case e, ok := <-ch.in: - if !ok { - // We don't want the input channel be accidentally closed - // via close() instead of Close(). If that happens, it is - // a misuse, do a panic as warning. - panic("async: misuse of unbounded channel, In() was closed") - } - ch.q = append(ch.q, e) - case <-ch.close: - ch.closed() - return - } - } - // If the remaining capacity is too small, we prefer to - // reallocate the entire buffer. - if cap(ch.q) < 1<<5 { - ch.q = make([]{{.Type}}, 0, 1<<10) - } - } -} - -func (ch *Unbounded{{.Name}}Chan) closed() { - close(ch.in) - for e := range ch.in { - ch.q = append(ch.q, e) - } - for len(ch.q) > 0 { - select { - case ch.out <- ch.q[0]: - ch.q[0] = nil // de-reference earlier to help GC - ch.q = ch.q[1:] - default: - } - } - close(ch.out) - close(ch.close) -} -`)) diff --git a/internal/driver/mobile/app/app.go b/internal/driver/mobile/app/app.go index dc057ecc23..505b74e74d 100644 --- a/internal/driver/mobile/app/app.go +++ b/internal/driver/mobile/app/app.go @@ -75,7 +75,7 @@ type PublishResult struct { } var theApp = &app{ - events: async.NewUnboundedInterfaceChan(), + events: async.NewUnboundedChan[any](), lifecycleStage: lifecycle.StageDead, publish: make(chan struct{}), publishResult: make(chan PublishResult), @@ -100,7 +100,7 @@ func (a *app) sendLifecycle(to lifecycle.Stage) { type app struct { filters []func(any) any - events *async.UnboundedInterfaceChan + events *async.UnboundedChan[any] lifecycleStage lifecycle.Stage publish chan struct{} publishResult chan PublishResult diff --git a/internal/driver/mobile/driver.go b/internal/driver/mobile/driver.go index b79664bcbf..7cad78172f 100644 --- a/internal/driver/mobile/driver.go +++ b/internal/driver/mobile/driver.go @@ -62,7 +62,7 @@ type driver struct { onConfigChanged func(*Configuration) painting bool running atomic.Bool - queuedFuncs *async.UnboundedFuncChan + queuedFuncs *async.UnboundedChan[func()] } // Declare conformity with Driver @@ -152,7 +152,7 @@ func (d *driver) Run() { app.Main(func(a app.App) { d.app = a settingsChange := make(chan fyne.Settings) - d.queuedFuncs = async.NewUnboundedFuncChan() + d.queuedFuncs = async.NewUnboundedChan[func()]() fyne.CurrentApp().Settings().AddChangeListener(settingsChange) draw := time.NewTicker(time.Second / 60) defer func() { From d40c6c5a6c0c64371cc17d485ed9c67bc0e04db8 Mon Sep 17 00:00:00 2001 From: Jacalz Date: Wed, 8 Jan 2025 14:57:23 +0100 Subject: [PATCH 2/2] Remove old mentions of generator --- internal/async/doc.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/internal/async/doc.go b/internal/async/doc.go index 7ea5bb9a1a..9ac614f9a2 100644 --- a/internal/async/doc.go +++ b/internal/async/doc.go @@ -1,5 +1,3 @@ -//go:generate go run gen.go - // Package async provides unbounded channel and queue structures that are // designed for caching unlimited number of a concrete type. For better // performance, a given type should be less or euqal than 16 bytes. @@ -17,6 +15,4 @@ // speed constantly. However, such a channel may be fairly used for event // delivering if the consumer of the channel consumes the incoming // forever, such as even processing. -// -// This package involves code generators, see gen.go for more details. package async