asset_configuration.go

v0.2.0
Doc Versions Source
1
package steward
2
3
import (
4
	"reflect"
5
	"unicode"
6
	"unicode/utf8"
7
8
	"github.com/soverenio/vanilla/throw"
9
10
	"go.bigb.es/auxilia/collect"
11
	"go.bigb.es/auxilia/fn"
12
)
13
14
var _ Asset = &configurationAsset{}
15
16
type configurationAsset struct {
17
	value             any
18
	subConfigurations []reflect.Value
19
}
20
21
func MustConfigurationAsset(value any) Asset {
22
	return fn.Must1(ConfigurationAsset(value))
23
}
24
25
func MustNewConfigurationAsset(value any) Asset { return MustConfigurationAsset(value) }
26
27
func ConfigurationAsset(value any) (Asset, error) {
28
	cfgAsset := &configurationAsset{value: value}
29
	return cfgAsset, cfgAsset.populateVerifyTop()
30
}
31
32
func NewConfigurationAsset(value any) (Asset, error) { return ConfigurationAsset(value) }
33
34
func (c *configurationAsset) asset() {}
35
36
func (c *configurationAsset) Name() string {
37
	return reflect.TypeOf(c.value).String()
38
}
39
40
func (c *configurationAsset) populateVerifyTop() error {
41
	topValue := reflect.ValueOf(c.value)
42
	c.subConfigurations = append(c.subConfigurations, topValue)
43
	return c.populateVerify(topValue, true)
44
}
45
46
func (c *configurationAsset) saveSubConfiguration(fieldDef reflect.StructField, value reflect.Value) {
47
	if fieldDef.Type.Kind() != reflect.Struct {
48
		return
49
	} else if _, ok := fieldDef.Tag.Lookup("config-section"); !ok {
50
		return
51
	}
52
53
	c.subConfigurations = append(c.subConfigurations, value)
54
}
55
56
func (c *configurationAsset) populateVerify(value reflect.Value, populate bool) error {
57
	switch value.Kind() {
58
	case reflect.Struct:
59
		ok := true
60
61
		structFieldIteratorFromType(value).Filter(func(pair structField) bool {
62
			r, _ := utf8.DecodeRuneInString(pair.First().Name)
63
			if r == utf8.RuneError {
64
				return false
65
			}
66
			return !unicode.IsLower(r)
67
		}).Apply(func(pair collect.Tuple2[reflect.StructField, reflect.Value]) {
68
			c.saveSubConfiguration(pair.Values())
69
70
			ok = ok && (c.populateVerify(pair.Second(), populate) == nil)
71
		})
72
73
		if !ok {
74
			return throw.New("failed")
75
		}
76
		return nil
77
	case reflect.Array:
78
		return nil
79
	case reflect.Slice:
80
		return nil
81
	case reflect.Map:
82
		return nil
83
	case reflect.Pointer:
84
		if value.IsNil() {
85
			return nil
86
		}
87
		return c.populateVerify(value.Elem(), populate)
88
	case reflect.Bool, reflect.String:
89
		return nil
90
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
91
		return nil
92
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
93
		return nil
94
	case reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
95
		return nil
96
	default:
97
		return throw.New("unexpected type for configurationAsset asset: " + value.Kind().String())
98
	}
99
}
100
101
func (c *configurationAsset) TryInject(object any) (injected bool) {
102
	objectValue := reflect.ValueOf(object)
103
104
	for _, config := range c.subConfigurations {
105
		if !typesEqual(objectValue.Type(), config.Type()) {
106
			continue
107
		}
108
109
		objectValue.Elem().Set(config)
110
		return true
111
	}
112
113
	return false
114
}
115
116
func (c *configurationAsset) TryInjectTo(component *serviceAsset, field string) (injected bool) {
117
	objectValue := component.reflectedValue.Elem().FieldByName(field)
118
119
	for _, config := range c.subConfigurations {
120
		if !typesEqual(objectValue.Type(), config.Type()) {
121
			continue
122
		}
123
124
		objectValue.Set(config)
125
126
		return true
127
	}
128
129
	return false
130
}
131

Source Files