Skip to content

Commit

Permalink
move locking into Stringer
Browse files Browse the repository at this point in the history
  • Loading branch information
linkdata committed Nov 21, 2024
1 parent ed391df commit cf6bb75
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 95 deletions.
50 changes: 4 additions & 46 deletions bind.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package jaws

import (
"fmt"
"sync"
"time"
)
Expand All @@ -21,18 +20,14 @@ var (
_ TimeSetter = Binding[time.Time]{}
)

func (bind Binding[T]) getLocked() T {
return *bind.P
}

func (bind Binding[T]) Get() (value T) {
if rl, ok := bind.L.(RLocker); ok {
rl.RLock()
value = bind.getLocked()
value = *bind.P
rl.RUnlock()
} else {
bind.L.Lock()
value = bind.getLocked()
value = *bind.P
bind.L.Unlock()
}
return
Expand All @@ -49,10 +44,6 @@ func (bind Binding[T]) Set(value T) (err error) {
return
}

func (bind Binding[T]) jawsGetLocked(*Element) T {
return bind.getLocked()
}

func (bind Binding[T]) JawsGet(*Element) T {
return bind.Get()
}
Expand All @@ -62,45 +53,15 @@ func (bind Binding[T]) JawsSet(elem *Element, value T) error {
}

func (bind Binding[T]) JawsGetTag(*Request) any {
if x, ok := any(*bind.P).(fmt.Stringer); ok {
return x
}
if x, ok := any(bind.P).(fmt.Stringer); ok {
return x
}
return bind.P
}

func (bind Binding[T]) JawsSetString(e *Element, val string) (err error) {
defer func() {
if e := recover(); e != nil {
if _, ok := any(*bind.P).(fmt.Stringer); ok {
err = ErrValueNotSettable
} else if _, ok := any(bind.P).(fmt.Stringer); ok {
err = ErrValueNotSettable
} else {
panic(e)
}
}
}()
return bind.JawsSet(e, any(val).(T))
}

func (bind Binding[T]) JawsGetString(e *Element) string {
if rl, ok := bind.L.(RLocker); ok {
rl.RLock()
defer rl.RUnlock()
} else {
bind.L.Lock()
defer bind.L.Unlock()
}
if x, ok := any(*bind.P).(fmt.Stringer); ok {
return x.String()
}
if x, ok := any(bind.P).(fmt.Stringer); ok {
return x.String()
}
return any(bind.jawsGetLocked(e)).(string)
return any(bind.JawsGet(e)).(string)
}

func (bind Binding[T]) JawsSetFloat(e *Element, val float64) (err error) {
Expand Down Expand Up @@ -132,10 +93,7 @@ func (bind Binding[T]) JawsSetTime(elem *Element, value time.Time) error {
// It implements Setter[T]. It also implements BoolSetter, FloatSetter, StringSetter and TimeSetter, but will panic
// if the underlying type T is not correct.
//
// It has special support for fmt.Stringer, and will call T.String() for JawsGetString()
// and return ErrValueNotSettable for JawsSetString().
//
// The pointer (or fmt.Stringer if applicable) will be used as the UI tag.
// The pointer will be used as the UI tag.
func Bind[T comparable](l sync.Locker, p *T) Binding[T] {
return Binding[T]{L: l, P: p}
}
37 changes: 29 additions & 8 deletions stringer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package jaws

import (
"fmt"
"sync"
)

type stringizer[T any] struct {
Expand All @@ -16,14 +17,34 @@ func (s stringizer[T]) JawsGetTag(*Request) any {
return s.v
}

// Stringer returns a fmt.Stringer using fmt.Sprint(*T)
// unless *T or T implements fmt.Stringer, in which case that will be returned directly.
func Stringer[T any](v *T) fmt.Stringer {
if x, ok := any(*v).(fmt.Stringer); ok {
return x
type lockedstringer struct {
l sync.Locker
s fmt.Stringer
}

func (s lockedstringer) String() (value string) {
if rl, ok := s.l.(RLocker); ok {
rl.RLock()
defer rl.RUnlock()
} else {
s.l.Lock()
defer s.l.Unlock()
}
return s.s.String()
}

func (s lockedstringer) JawsGetTag(*Request) any {
return s.s
}

// Stringer returns a lock protected fmt.Stringer using fmt.Sprint(*T)
// unless *T or T implements fmt.Stringer, in which case that will be used.
func Stringer[T any](l sync.Locker, p *T) fmt.Stringer {
if x, ok := any(*p).(fmt.Stringer); ok {
return lockedstringer{l, x}
}
if x, ok := any(v).(fmt.Stringer); ok {
return x
if x, ok := any(p).(fmt.Stringer); ok {
return lockedstringer{l, x}
}
return stringizer[T]{v}
return lockedstringer{l, stringizer[T]{p}}
}
51 changes: 10 additions & 41 deletions stringer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,70 +23,39 @@ func TestStringer(t *testing.T) {
var mu2 sync.RWMutex

txt := "text"
stringer := Stringer(&txt)
if s := Bind(&mu, &stringer).JawsGetString(nil); s != "text" {
stringer := Stringer(&mu, &txt)
if s := stringer.String(); s != "text" {
t.Error(s)
}
if tags := MustTagExpand(nil, stringer); !reflect.DeepEqual(tags, []any{&txt}) {
t.Error(tags)
}

num := int(123)
stringer = Stringer(&num)
if s := Bind(&mu, &stringer).JawsGetString(nil); s != "123" {
stringer = Stringer(&mu, &num)
if s := stringer.String(); s != "123" {
t.Error(s)
}
if tags := MustTagExpand(nil, stringer); !reflect.DeepEqual(tags, []any{&num}) {
t.Error(tags)
}

teststringer := testStringer{}
stringer = Stringer(&teststringer)
if !reflect.DeepEqual(stringer, teststringer) {
t.Errorf("%#v != %#v", stringer, teststringer)
}
if tags := MustTagExpand(nil, stringer); !reflect.DeepEqual(tags, []any{teststringer}) {
t.Errorf("%#v", tags)
}
b1 := Bind(&mu, &stringer)
if s := b1.JawsGetString(nil); s != (testStringer{}).String() {
stringer = Stringer(&mu, &teststringer)
if s := stringer.String(); s != (testStringer{}).String() {
t.Error(s)
}
if tags := MustTagExpand(nil, b1); !reflect.DeepEqual(tags, []any{teststringer}) {
if tags := MustTagExpand(nil, stringer); !reflect.DeepEqual(tags, []any{teststringer}) {
t.Errorf("%#v", tags)
}
if err := b1.JawsSetString(nil, "x"); err != ErrValueNotSettable {
t.Error(err)
}

testptrstringer := &testPtrStringer{}
stringer = Stringer(testptrstringer)
if !reflect.DeepEqual(stringer, testptrstringer) {
t.Errorf("%#v != %#v", stringer, testptrstringer)
}
if tags := MustTagExpand(nil, stringer); !reflect.DeepEqual(tags, []any{testptrstringer}) {
t.Errorf("%#v", tags)
}

b2 := Bind(&mu2, &stringer)
if s := b2.JawsGetString(nil); s != (&testPtrStringer{}).String() {
stringer = Stringer(&mu2, testptrstringer)
if s := stringer.String(); s != (&testPtrStringer{}).String() {
t.Error(s)
}
if tags := MustTagExpand(nil, b2); !reflect.DeepEqual(tags, []any{testptrstringer}) {
if tags := MustTagExpand(nil, stringer); !reflect.DeepEqual(tags, []any{testptrstringer}) {
t.Errorf("%#v", tags)
}
if err := b2.JawsSetString(nil, "x"); err != ErrValueNotSettable {
t.Error(err)
}

b3 := Bind(&mu2, testptrstringer)
if s := b3.JawsGetString(nil); s != (&testPtrStringer{}).String() {
t.Error(s)
}
if tags := MustTagExpand(nil, b3); !reflect.DeepEqual(tags, []any{testptrstringer}) {
t.Errorf("%#v", tags)
}
if err := b3.JawsSetString(nil, "x"); err != ErrValueNotSettable {
t.Error(err)
}
}

0 comments on commit cf6bb75

Please sign in to comment.