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