-
Notifications
You must be signed in to change notification settings - Fork 118
/
option.go
118 lines (98 loc) · 2.82 KB
/
option.go
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package vm
import (
"encoding/json"
"fmt"
"github.com/ava-labs/hypersdk/api"
"github.com/ava-labs/hypersdk/chain"
"github.com/ava-labs/hypersdk/event"
)
type Options struct {
builder bool
gossiper bool
blockSubscriptionFactories []event.SubscriptionFactory[*chain.ExecutedBlock]
vmAPIHandlerFactories []api.HandlerFactory[api.VM]
}
type optionFunc func(vm api.VM, configBytes []byte) (Opt, error)
type OptionFunc[T any] func(vm api.VM, config T) (Opt, error)
type Option struct {
Namespace string
optionFunc optionFunc
}
func newOptionWithBytes(namespace string, optionFunc optionFunc) Option {
return Option{
Namespace: namespace,
optionFunc: optionFunc,
}
}
// NewOption returns an option with:
// 1) A namespace to define the key in the VM's JSON config that should be supplied to this option
// 2) A default config value the VM will directly unmarshal into
// 3) An option function that takes the VM and resulting config value as arguments
func NewOption[T any](namespace string, defaultConfig T, optionFunc OptionFunc[T]) Option {
config := defaultConfig
configOptionFunc := func(vm api.VM, configBytes []byte) (Opt, error) {
if len(configBytes) > 0 {
if err := json.Unmarshal(configBytes, &config); err != nil {
return nil, fmt.Errorf("failed to unmarshal %q config %q: %w", namespace, string(configBytes), err)
}
}
return optionFunc(vm, config)
}
return newOptionWithBytes(namespace, configOptionFunc)
}
func WithBuilder() Opt {
return newFuncOption(func(o *Options) {
o.builder = true
})
}
func WithGossiper() Opt {
return newFuncOption(func(o *Options) {
o.gossiper = true
})
}
func WithManual() Option {
return NewOption[struct{}](
"manual",
struct{}{},
func(_ api.VM, _ struct{}) (Opt, error) {
return newFuncOption(func(o *Options) {
WithBuilder().apply(o)
WithGossiper().apply(o)
}), nil
},
)
}
func WithBlockSubscriptions(subscriptions ...event.SubscriptionFactory[*chain.ExecutedBlock]) Opt {
return newFuncOption(func(o *Options) {
o.blockSubscriptionFactories = append(o.blockSubscriptionFactories, subscriptions...)
})
}
func WithVMAPIs(apiHandlerFactories ...api.HandlerFactory[api.VM]) Opt {
return newFuncOption(func(o *Options) {
o.vmAPIHandlerFactories = append(o.vmAPIHandlerFactories, apiHandlerFactories...)
})
}
type Opt interface {
apply(*Options)
}
// NewOpt mixes a list of Opt in a new one Opt.
func NewOpt(opts ...Opt) Opt {
return newFuncOption(func(o *Options) {
for _, opt := range opts {
opt.apply(o)
}
})
}
type funcOption struct {
f func(*Options)
}
func (fdo *funcOption) apply(do *Options) {
fdo.f(do)
}
func newFuncOption(f func(*Options)) *funcOption {
return &funcOption{
f: f,
}
}