diff --git a/pkg/app/html-mount.new.txt b/pkg/app/html-mount.new.txt index d774c7933..5960d66bb 100644 --- a/pkg/app/html-mount.new.txt +++ b/pkg/app/html-mount.new.txt @@ -5,6 +5,6 @@ goos: darwin goarch: arm64 pkg: github.com/maxence-charriere/go-app/v9/pkg/app -BenchmarkMountHTMLElement-10 52202 23502 ns/op 140310 B/op 72 allocs/op +BenchmarkMountHTMLElement-10 52926 22826 ns/op 140279 B/op 71 allocs/op PASS -ok github.com/maxence-charriere/go-app/v9/pkg/app 2.818s +ok github.com/maxence-charriere/go-app/v9/pkg/app 2.692s diff --git a/pkg/app/node.go b/pkg/app/node.go index e530f81c0..6ab126119 100644 --- a/pkg/app/node.go +++ b/pkg/app/node.go @@ -6,8 +6,6 @@ import ( "net/url" "reflect" "strings" - - "github.com/maxence-charriere/go-app/v9/pkg/errors" ) // UI is the interface that describes a user interface element such as @@ -97,37 +95,44 @@ const ( // // It should be used only when implementing components that can accept content // with variadic arguments like HTML elements Body method. -func FilterUIElems(uis ...UI) []UI { - if len(uis) == 0 { +func FilterUIElems(v ...UI) []UI { + if len(v) == 0 { return nil } - elems := make([]UI, 0, len(uis)) + remove := func(i int) { + copy(v[i:], v[i+1:]) + v[len(v)-1] = nil + v = v[:len(v)-1] + } + + var b []UI + replaceAt := func(i int, s ...UI) { + b = append(b, v[i+1:]...) + v = append(v[:i], s...) + v = append(v, b...) + b = b[:0] + } - for _, n := range uis { - // Ignore nil elements: - if v := reflect.ValueOf(n); n == nil || - v.Kind() == reflect.Ptr && v.IsNil() { + for i := len(v) - 1; i >= 0; i-- { + e := v[i] + if ev := reflect.ValueOf(e); e == nil || ev.Kind() == reflect.Pointer && ev.IsNil() { + remove(i) continue } - switch n.Kind() { + switch e.Kind() { case SimpleText, HTML, Component, RawHTML: - elems = append(elems, n) case Selector: - elems = append(elems, n.getChildren()...) + replaceAt(i, e.getChildren()...) default: - panic(errors.New("filtering ui elements failed"). - Tag("reason", "unexpected element type found"). - Tag("kind", n.Kind()). - Tag("name", n.name()), - ) + remove(i) } } - return elems + return v } func mount(d Dispatcher, n UI) error { diff --git a/pkg/app/node_test.go b/pkg/app/node_test.go index 4c99bac3e..e2273e902 100644 --- a/pkg/app/node_test.go +++ b/pkg/app/node_test.go @@ -1,6 +1,7 @@ package app import ( + "fmt" "testing" "github.com/stretchr/testify/require" @@ -42,6 +43,7 @@ func TestKindString(t *testing.T) { func TestFilterUIElems(t *testing.T) { var nilText *text + var foo *foo simpleText := Text("hello") @@ -49,10 +51,29 @@ func TestFilterUIElems(t *testing.T) { simpleText, } - res := FilterUIElems(nil, nilText, simpleText) + res := FilterUIElems(nil, nilText, simpleText, foo) require.Equal(t, expectedResult, res) } +func BenchmarkFilterUIElems(b *testing.B) { + for n := 0; n < b.N; n++ { + FilterUIElems(Div(). + Class("shell"). + Body( + H1().Class("title"). + Text("Hello"), + Input(). + Type("text"). + Class("in"). + Value("World"). + Placeholder("Type a name."). + OnChange(func(ctx Context, e Event) { + fmt.Println("Yo!") + }), + )) + } +} + type mountTest struct { scenario string node UI