-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinternal.go
More file actions
83 lines (72 loc) · 2.47 KB
/
Copy pathinternal.go
File metadata and controls
83 lines (72 loc) · 2.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package signals
import "reflect"
// trackDependencyHelper is a shared helper for subscribing to dependencies with type erasure.
// It handles the complexity of subscribing to ReadonlySignal[X] where X is unknown at compile time.
//
// This helper is used by both Computed and Effect to avoid code duplication.
// The onChange callback is called whenever the dependency changes.
func trackDependencyHelper(dep any, onChange func()) Unsubscribe {
// Helper interface to extract SubscribeForever
type subscriber interface {
SubscribeForever(fn func(any)) Unsubscribe
}
// First, try direct interface assertion
if sub, ok := dep.(subscriber); ok {
return sub.SubscribeForever(func(_ any) {
onChange()
})
}
// If that fails, handle common concrete types using type switch
// This avoids reflection overhead for the most common types
switch d := dep.(type) {
case ReadonlySignal[int]:
return d.SubscribeForever(func(_ int) { onChange() })
case ReadonlySignal[string]:
return d.SubscribeForever(func(_ string) { onChange() })
case ReadonlySignal[bool]:
return d.SubscribeForever(func(_ bool) { onChange() })
case ReadonlySignal[float64]:
return d.SubscribeForever(func(_ float64) { onChange() })
case ReadonlySignal[int64]:
return d.SubscribeForever(func(_ int64) { onChange() })
default:
// For any other type, use reflection as a fallback
return subscribeAnyType(dep, onChange)
}
}
// subscribeAnyType uses reflection to subscribe to any ReadonlySignal[X] type.
// This is a fallback for types not covered by the type switch in trackDependencyHelper.
func subscribeAnyType(dep any, onChange func()) Unsubscribe {
// Use reflection to call SubscribeForever on any ReadonlySignal type
val := reflect.ValueOf(dep)
if !val.IsValid() {
return func() {}
}
// Look for SubscribeForever method
method := val.MethodByName("SubscribeForever")
if !method.IsValid() {
return func() {}
}
// Validate method signature
fnType := method.Type()
if fnType.NumIn() != 1 || fnType.NumOut() != 1 {
return func() {}
}
// Create a callback using reflection
callbackType := fnType.In(0)
callback := reflect.MakeFunc(callbackType, func(_ []reflect.Value) []reflect.Value {
onChange()
return nil
})
// Call SubscribeForever(callback)
results := method.Call([]reflect.Value{callback})
if len(results) != 1 {
return func() {}
}
// Extract Unsubscribe function
unsubVal := results[0]
if unsub, ok := unsubVal.Interface().(Unsubscribe); ok {
return unsub
}
return func() {}
}