Skip to content

Commit

Permalink
Merge pull request #5376 from Jacalz/async-map-helper
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacalz authored Jan 9, 2025
2 parents e6225b5 + dac93f7 commit 1bfc24c
Show file tree
Hide file tree
Showing 22 changed files with 335 additions and 233 deletions.
8 changes: 4 additions & 4 deletions app/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/internal/app"
"fyne.io/fyne/v2/internal/async"
"fyne.io/fyne/v2/internal/build"
"fyne.io/fyne/v2/theme"
)
Expand Down Expand Up @@ -37,8 +38,8 @@ type settings struct {
themeSpecified bool
variant fyne.ThemeVariant

changeListeners sync.Map // map[chan fyne.Settings]bool
watcher any // normally *fsnotify.Watcher or nil - avoid import in this file
changeListeners async.Map[chan fyne.Settings, bool]
watcher any // normally *fsnotify.Watcher or nil - avoid import in this file

schema SettingsSchema
}
Expand Down Expand Up @@ -116,8 +117,7 @@ func (s *settings) AddChangeListener(listener chan fyne.Settings) {
}

func (s *settings) apply() {
s.changeListeners.Range(func(key, _ any) bool {
listener := key.(chan fyne.Settings)
s.changeListeners.Range(func(listener chan fyne.Settings, _ bool) bool {
select {
case listener <- s:
default:
Expand Down
7 changes: 4 additions & 3 deletions data/binding/binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"sync"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/internal/async"
)

var (
Expand Down Expand Up @@ -57,7 +58,7 @@ func (l *listener) DataChanged() {
}

type base struct {
listeners sync.Map // map[DataListener]bool
listeners async.Map[DataListener, bool]

lock sync.RWMutex
}
Expand All @@ -75,8 +76,8 @@ func (b *base) RemoveListener(l DataListener) {

func (b *base) trigger() {
var listeners []DataListener
b.listeners.Range(func(key, _ any) bool {
listeners = append(listeners, key.(DataListener))
b.listeners.Range(func(listener DataListener, _ bool) bool {
listeners = append(listeners, listener)
return true
})

Expand Down
17 changes: 4 additions & 13 deletions data/binding/binding_test.go
Original file line number Diff line number Diff line change
@@ -1,34 +1,25 @@
package binding

import (
"sync"
"testing"

"github.com/stretchr/testify/assert"
)

func syncMapLen(m *sync.Map) (n int) {
m.Range(func(_, _ any) bool {
n++
return true
})
return
}

type simpleItem struct {
base
}

func TestBase_AddListener(t *testing.T) {
data := &simpleItem{}
assert.Equal(t, 0, syncMapLen(&data.listeners))
assert.Equal(t, 0, data.listeners.Len())

called := false
fn := NewDataListener(func() {
called = true
})
data.AddListener(fn)
assert.Equal(t, 1, syncMapLen(&data.listeners))
assert.Equal(t, 1, data.listeners.Len())
assert.True(t, called)
}

Expand All @@ -40,9 +31,9 @@ func TestBase_RemoveListener(t *testing.T) {
data := &simpleItem{}
data.listeners.Store(fn, true)

assert.Equal(t, 1, syncMapLen(&data.listeners))
assert.Equal(t, 1, data.listeners.Len())
data.RemoveListener(fn)
assert.Equal(t, 0, syncMapLen(&data.listeners))
assert.Equal(t, 0, data.listeners.Len())

data.trigger()
assert.False(t, called)
Expand Down
4 changes: 2 additions & 2 deletions data/binding/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ type prefBound{{ .Name }} struct {
func BindPreference{{ .Name }}(key string, p fyne.Preferences) {{ .Name }} {
binds := prefBinds.getBindings(p)
if binds != nil {
if listen := binds.getItem(key); listen != nil {
if listen, ok := binds.Load(key); listen != nil && ok {
if l, ok := listen.({{ .Name }}); ok {
return l
}
Expand All @@ -145,7 +145,7 @@ func BindPreference{{ .Name }}(key string, p fyne.Preferences) {{ .Name }} {
listen := &prefBound{{ .Name }}{key: key, p: p}
binds = prefBinds.ensurePreferencesAttached(p)
binds.setItem(key, listen)
binds.Store(key, listen)
return listen
}
Expand Down
8 changes: 4 additions & 4 deletions data/binding/listbinding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ type simpleList struct {

func TestListBase_AddListener(t *testing.T) {
data := &simpleList{}
assert.Equal(t, 0, syncMapLen(&data.listeners))
assert.Equal(t, 0, data.listeners.Len())

called := false
fn := NewDataListener(func() {
called = true
})
data.AddListener(fn)
assert.Equal(t, 1, syncMapLen(&data.listeners))
assert.Equal(t, 1, data.listeners.Len())

data.trigger()
assert.True(t, called)
Expand Down Expand Up @@ -57,9 +57,9 @@ func TestListBase_RemoveListener(t *testing.T) {
data := &simpleList{}
data.listeners.Store(fn, true)

assert.Equal(t, 1, syncMapLen(&data.listeners))
assert.Equal(t, 1, data.listeners.Len())
data.RemoveListener(fn)
assert.Equal(t, 0, syncMapLen(&data.listeners))
assert.Equal(t, 0, data.listeners.Len())

data.trigger()
assert.False(t, called)
Expand Down
34 changes: 9 additions & 25 deletions data/binding/pref_helper.go
Original file line number Diff line number Diff line change
@@ -1,42 +1,29 @@
package binding

import (
"sync"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/internal/async"
)

type preferenceItem interface {
checkForChange()
}

type preferenceBindings struct {
items sync.Map // map[string]preferenceItem
}

func (b *preferenceBindings) getItem(key string) preferenceItem {
val, loaded := b.items.Load(key)
if !loaded {
return nil
}
return val.(preferenceItem)
async.Map[string, preferenceItem]
}

func (b *preferenceBindings) list() []preferenceItem {
ret := []preferenceItem{}
b.items.Range(func(_, val any) bool {
ret = append(ret, val.(preferenceItem))
b.Range(func(_ string, item preferenceItem) bool {
ret = append(ret, item)
return true
})
return ret
}

func (b *preferenceBindings) setItem(key string, item preferenceItem) {
b.items.Store(key, item)
}

type preferencesMap struct {
prefs sync.Map // map[fyne.Preferences]*preferenceBindings
prefs async.Map[fyne.Preferences, *preferenceBindings]

appPrefs fyne.Preferences // the main application prefs, to check if it changed...
}
Expand All @@ -48,11 +35,11 @@ func newPreferencesMap() *preferencesMap {
func (m *preferencesMap) ensurePreferencesAttached(p fyne.Preferences) *preferenceBindings {
binds, loaded := m.prefs.LoadOrStore(p, &preferenceBindings{})
if loaded {
return binds.(*preferenceBindings)
return binds
}

p.AddChangeListener(func() { m.preferencesChanged(fyne.CurrentApp().Preferences()) })
return binds.(*preferenceBindings)
return binds
}

func (m *preferencesMap) getBindings(p fyne.Preferences) *preferenceBindings {
Expand All @@ -63,11 +50,8 @@ func (m *preferencesMap) getBindings(p fyne.Preferences) *preferenceBindings {
m.migratePreferences(m.appPrefs, p)
}
}
binds, loaded := m.prefs.Load(p)
if !loaded {
return nil
}
return binds.(*preferenceBindings)
binds, _ := m.prefs.Load(p)
return binds
}

func (m *preferencesMap) preferencesChanged(p fyne.Preferences) {
Expand Down
16 changes: 8 additions & 8 deletions data/binding/preference.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type prefBoundBool struct {
func BindPreferenceBool(key string, p fyne.Preferences) Bool {
binds := prefBinds.getBindings(p)
if binds != nil {
if listen := binds.getItem(key); listen != nil {
if listen, ok := binds.Load(key); listen != nil && ok {
if l, ok := listen.(Bool); ok {
return l
}
Expand All @@ -35,7 +35,7 @@ func BindPreferenceBool(key string, p fyne.Preferences) Bool {

listen := &prefBoundBool{key: key, p: p}
binds = prefBinds.ensurePreferencesAttached(p)
binds.setItem(key, listen)
binds.Store(key, listen)
return listen
}

Expand Down Expand Up @@ -80,7 +80,7 @@ type prefBoundFloat struct {
func BindPreferenceFloat(key string, p fyne.Preferences) Float {
binds := prefBinds.getBindings(p)
if binds != nil {
if listen := binds.getItem(key); listen != nil {
if listen, ok := binds.Load(key); listen != nil && ok {
if l, ok := listen.(Float); ok {
return l
}
Expand All @@ -90,7 +90,7 @@ func BindPreferenceFloat(key string, p fyne.Preferences) Float {

listen := &prefBoundFloat{key: key, p: p}
binds = prefBinds.ensurePreferencesAttached(p)
binds.setItem(key, listen)
binds.Store(key, listen)
return listen
}

Expand Down Expand Up @@ -135,7 +135,7 @@ type prefBoundInt struct {
func BindPreferenceInt(key string, p fyne.Preferences) Int {
binds := prefBinds.getBindings(p)
if binds != nil {
if listen := binds.getItem(key); listen != nil {
if listen, ok := binds.Load(key); listen != nil && ok {
if l, ok := listen.(Int); ok {
return l
}
Expand All @@ -145,7 +145,7 @@ func BindPreferenceInt(key string, p fyne.Preferences) Int {

listen := &prefBoundInt{key: key, p: p}
binds = prefBinds.ensurePreferencesAttached(p)
binds.setItem(key, listen)
binds.Store(key, listen)
return listen
}

Expand Down Expand Up @@ -190,7 +190,7 @@ type prefBoundString struct {
func BindPreferenceString(key string, p fyne.Preferences) String {
binds := prefBinds.getBindings(p)
if binds != nil {
if listen := binds.getItem(key); listen != nil {
if listen, ok := binds.Load(key); listen != nil && ok {
if l, ok := listen.(String); ok {
return l
}
Expand All @@ -200,7 +200,7 @@ func BindPreferenceString(key string, p fyne.Preferences) String {

listen := &prefBoundString{key: key, p: p}
binds = prefBinds.ensurePreferencesAttached(p)
binds.setItem(key, listen)
binds.Store(key, listen)
return listen
}

Expand Down
8 changes: 4 additions & 4 deletions data/binding/treebinding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import (

func TestTreeBase_AddListener(t *testing.T) {
data := newSimpleTree()
assert.Equal(t, 0, syncMapLen(&data.listeners))
assert.Equal(t, 0, data.listeners.Len())

called := false
fn := NewDataListener(func() {
called = true
})
data.AddListener(fn)
assert.Equal(t, 1, syncMapLen(&data.listeners))
assert.Equal(t, 1, data.listeners.Len())

data.trigger()
assert.True(t, called)
Expand Down Expand Up @@ -54,9 +54,9 @@ func TestTreeBase_RemoveListener(t *testing.T) {
data := newSimpleTree()
data.listeners.Store(fn, true)

assert.Equal(t, 1, syncMapLen(&data.listeners))
assert.Equal(t, 1, data.listeners.Len())
data.RemoveListener(fn)
assert.Equal(t, 0, syncMapLen(&data.listeners))
assert.Equal(t, 0, data.listeners.Len())

data.trigger()
assert.False(t, called)
Expand Down
65 changes: 65 additions & 0 deletions internal/async/map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package async

import "sync"

// Map is a generic wrapper around [sync.Map].
type Map[K, V any] struct {
sync.Map
}

// Delete deletes the value for a key.
func (m *Map[K, V]) Delete(key K) {
m.Map.Delete(key)
}

// Len returns the length of the map. It is O(n) over the number of items.
func (m *Map[K, V]) Len() (count int) {
m.Map.Range(func(_, _ any) bool {
count++
return true
})
return count
}

// Load returns the value stored in the map for a key, or nil if no value is present.
// The ok result indicates whether value was found in the map.
func (m *Map[K, V]) Load(key K) (value V, ok bool) {
val, ok := m.Map.Load(key)
if val == nil {
return *new(V), ok
}
return val.(V), ok
}

// LoadAndDelete deletes the value for a key, returning the previous value if any.
// The loaded result reports whether the key was present.
func (m *Map[K, V]) LoadAndDelete(key K) (value V, loaded bool) {
val, loaded := m.Map.LoadAndDelete(key)
if val == nil {
return *new(V), loaded
}
return val.(V), loaded
}

// LoadOrStore returns the existing value for the key if present.
// Otherwise, it stores and returns the given value.
// The loaded result is true if the value was loaded, false if stored.
func (m *Map[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) {
act, loaded := m.Map.LoadOrStore(key, value)
if act == nil {
return *new(V), loaded
}
return act.(V), loaded
}

// Range calls f sequentially for each key and value present in the map. If f returns false, range stops the iteration.
func (m *Map[K, V]) Range(f func(key K, value V) bool) {
m.Map.Range(func(key, value any) bool {
return f(key.(K), value.(V))
})
}

// Store sets the value for a key.
func (m *Map[K, V]) Store(key K, value V) {
m.Map.Store(key, value)
}
Loading

0 comments on commit 1bfc24c

Please sign in to comment.