Repository: mlange-42/arche
Pull request #354 (2024-01-30 19:39:07)

Fix IsRelation check to allow for non-struct components

coveralls: ## Pull Request Test Coverage Report for [Build 7716551971](https://coveralls.io/builds/65392367)


* **0** of **2**   **(100.0%)**  changed or added relevant lines in **2** files are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage remained the same at **100.0%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/65392367/badge)](https://coveralls.io/builds/65392367) |
| :-- | --: |
| Change from base [Build 7712747421](https://coveralls.io/builds/65383982): |  0.0% |
| Covered Lines: | 6149 |
| Relevant Lines: | 6149 |

---
##### 💛  - [Coveralls](https://coveralls.io)


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 064fe61..52ca113 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
 # Changelog
 
+## [[v0.10.1]](https://github.com/mlange-42/arche/compare/v0.10.0...v0.10.1)
+
+### Bugfixes
+
+* Fix IsRelation check to allow for non-struct components, like type aliases (#354)
+
+### Other
+
+* Repository [arche-demo](https://github.com/mlange-42/arche-demo) provides a [live demo](https://mlange-42.github.io/arche-demo/)
+of several models built with Arche.
+
 ## [[v0.10.0]](https://github.com/mlange-42/arche/compare/v0.9.0...v0.10.0)
 
 ### Highlights
diff --git a/ecs/registry.go b/ecs/registry.go
index cc677b8..79504ca 100644
--- a/ecs/registry.go
+++ b/ecs/registry.go
@@ -73,7 +73,7 @@ func (r *componentRegistry) unregisterLastComponent() {
 }
 
 func (r *componentRegistry) isRelation(tp reflect.Type) bool {
-	if tp.NumField() == 0 {
+	if tp.Kind() != reflect.Struct || tp.NumField() == 0 {
 		return false
 	}
 	field := tp.Field(0)
diff --git a/generic/compiled.go b/generic/compiled.go
index ad18c84..72617cd 100644
--- a/generic/compiled.go
+++ b/generic/compiled.go
@@ -55,7 +55,7 @@ func (q *compiledQuery) Compile(w *ecs.World, include, optional, exclude []Comp,
 			panic(fmt.Sprintf("relation component %v not in filter", targetType))
 		}
 		isRelation := false
-		if targetType.NumField() > 0 {
+		if targetType.Kind() == reflect.Struct && targetType.NumField() > 0 {
 			field := targetType.Field(0)
 			isRelation = field.Type == relationType && field.Name == relationType.Name()
 		}


Test patch:
diff --git a/ecs/types_test.go b/ecs/types_test.go
index 8705bf4..d1abf8a 100644
--- a/ecs/types_test.go
+++ b/ecs/types_test.go
@@ -62,6 +62,12 @@ type genericComp[T any] struct {
 	Value T
 }
 
+type callbackComp1 struct {
+	Callback func(a, b float64) float64
+}
+
+type callbackComp2 = func(a, b float64) float64
+
 func TestTypeSizes(t *testing.T) {
 	printTypeSize[Entity]()
 	printTypeSize[entityIndex]()
@@ -116,3 +122,37 @@ func TestGenericComponents(t *testing.T) {
 	assert.True(t, world.Has(e3, id1))
 	assert.True(t, world.Has(e3, id2))
 }
+
+func TestCallbackComponents(t *testing.T) {
+	world := NewWorld()
+
+	id1 := ComponentID[callbackComp1](&world)
+	id2 := ComponentID[callbackComp2](&world)
+
+	e1 := world.NewEntityWith(
+		Component{
+			ID:   id1,
+			Comp: &callbackComp1{Callback: func(a, b float64) float64 { return a + b }},
+		},
+	)
+
+	cb2 := callbackComp2(func(a, b float64) float64 { return a * b })
+	e2 := world.NewEntityWith(
+		Component{
+			ID:   id1,
+			Comp: &callbackComp1{Callback: func(a, b float64) float64 { return a - b }},
+		},
+		Component{
+			ID:   id2,
+			Comp: &cb2,
+		},
+	)
+
+	c1 := (*callbackComp1)(world.Get(e1, id1))
+	c2 := (*callbackComp1)(world.Get(e2, id1))
+	c3 := (*callbackComp2)(world.Get(e2, id2))
+
+	assert.Equal(t, 3.0, c1.Callback(2, 1))
+	assert.Equal(t, 1.0, c2.Callback(2, 1))
+	assert.Equal(t, 6.0, (*c3)(2, 3))
+}