forked from devfile/api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathunion_implementation.go
103 lines (90 loc) · 2.68 KB
/
union_implementation.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
package v1alpha1
import (
"errors"
"reflect"
)
func visitUnion(union interface{}, visitor interface{}) (err error) {
visitorValue := reflect.ValueOf(visitor)
unionValue := reflect.ValueOf(union)
oneMemberPresent := false
typeOfVisitor := visitorValue.Type()
for i := 0; i < visitorValue.NumField(); i++ {
unionMemberToRead := typeOfVisitor.Field(i).Name
unionMember := unionValue.FieldByName(unionMemberToRead)
if !unionMember.IsZero() {
if oneMemberPresent {
err = errors.New("Only one element should be set in union: " + unionValue.Type().Name())
return
}
oneMemberPresent = true
visitorFunction := visitorValue.Field(i)
if visitorFunction.IsNil() {
return
}
results := visitorFunction.Call([]reflect.Value{unionMember})
if !results[0].IsNil() {
err = results[0].Interface().(error)
}
return
}
}
return
}
func simplifyUnion(union Union, visitorType reflect.Type) {
_ = normalizeUnion(union, visitorType)
*union.discriminator() = ""
}
func normalizeUnion(union Union, visitorType reflect.Type) error {
err := updateDiscriminator(union, visitorType)
if err != nil {
return err
}
err = cleanupValues(union, visitorType)
if err != nil {
return err
}
return nil
}
func updateDiscriminator(union Union, visitorType reflect.Type) error {
unionValue := reflect.ValueOf(union)
if union.discriminator() == nil {
return errors.New("Discriminator should not be 'nil' in union: " + unionValue.Type().Name())
}
if *union.discriminator() != "" {
// Nothing to do
return nil
}
oneMemberPresent := false
for i := 0; i < visitorType.NumField(); i++ {
unionMemberToRead := visitorType.Field(i).Name
unionMember := unionValue.Elem().FieldByName(unionMemberToRead)
if !unionMember.IsZero() {
if oneMemberPresent {
return errors.New("Discriminator cannot be deduced from 2 values in union: " + unionValue.Type().Name())
}
oneMemberPresent = true
*(union.discriminator()) = unionMemberToRead
}
}
return nil
}
func cleanupValues(union Union, visitorType reflect.Type) error {
unionValue := reflect.ValueOf(union)
if union.discriminator() == nil {
return errors.New("Discriminator should not be 'nil' in union: " + unionValue.Type().Name())
}
if *union.discriminator() == "" {
// Nothing to do
return errors.New("Values cannot be cleaned up without a discriminator in union: " + unionValue.Type().Name())
}
for i := 0; i < visitorType.NumField(); i++ {
unionMemberToRead := visitorType.Field(i).Name
unionMember := unionValue.Elem().FieldByName(unionMemberToRead)
if !unionMember.IsZero() {
if unionMemberToRead != *union.discriminator() {
unionMember.Set(reflect.Zero(unionMember.Type()))
}
}
}
return nil
}